BEENOSの越境ECを実現する技術について(アクセス元判別バナー編)
初投稿に記載したように、BEENOSの主軸事業は越境ECです。越境ECサービスは複数のプロダクトから構成されていて、使われている技術も様々です。
今回は、我々が「アクセス元判別バナー」と呼んでいるプロダクトで使われている要素技術「JSONP」について説明したいと思います。
JSONPは、BEENOSオリジナルの技術ではなく、広く一般に使用されている技術です(例えばGoogle Tag Managerで使用されています)。ですがその動作原理は分かりやすいものではないため、コードを交えて説明します。
なぜアクセス元判別バナーを提供しているのか
BEENOSの越境ECサービスの一つに、海外のお客様に代わって日本のECサイトで商品を購入しお届けする、Buyeeというサービスがあります。Buyeeのサービスの流れは次のようになっています。
海外のお客様は、直接Buyeeに来られることもあれば、Buyeeと連携しているECサイトに来られることもあります。当該ECサイトは、海外のお客様の場合はBuyeeに誘導を行いたいので、それを実現するために、アクセス元判別バナーをサイト内に組み込んでいただいています。
例として、BEENOSのグループ会社であるBeeCruise株式会社が展開している9.kyuuのサイトを見てみましょう。
日本国内から9.kyuuの商品ページにアクセスすると次のように通常表示されます。
同じページを日本国外からアクセスすると、次のようにBuyeeに誘導するバナーが表示されます。
このような動的な処理を行うプログラムを組む方法はいくらでもありますが、Buyeeとの連携開始、つまり海外販売開始のコストを少しでも下げていただくために、JavaScriptタグを設置するだけで済むアクセス元判別バナーを提供しています。
ただしこの際に不都合になってくるのが「同一生成元ポリシー」です。
同一生成元ポリシー
セキュリティ上のリスクを緩和するために、ブラウザー等に実装されている「同一生成元ポリシー」という制約により、webページは通常、自分を生成したドメイン以外のドメインのサーバーと通信することはできません。
なぜこのような制約があるのかと言うと、この制約がない場合、例えばログインしないと閲覧できない情報のあるサイトにログインしている時に、他の生成元のサイトからそれを取得されるなどの危険が生じるからです。
では「同一生成元」とは何でしょうか。
webブラウザーは「スキーム」「ホスト」「ポート」の三つ全てが同一の元を、同じ生成元とみなします。https://beenos.comを例に挙げると、正確にはhttps://beenos.com:443/となりますが、httpsがスキーム、beenos.comがホスト、443がポートになります。
アクセス元を判別するなどの実処理は、web APIとしてBuyeeのサーバーで動作していて、ECサイトの生成元とは異なります。しかし、ECサイトに設置したJavaScriptタグから、Buyeeのweb APIを呼び出す必要があります。これを解決するのがJSONPという技術です。
JSONP
Wikipediaから一部分を引用します。
HTMLのscriptタグのsrc属性には別ドメインのURLを指定して通信することができるという点を利用することによって別ドメインのサーバからデータを取得することが可能になる。JSONPでは、通常、上記src属性のレスポンスの内容はjavascript関数呼び出しの形式となるため、src属性に指定するURLにその関数の名前をクエリ文字列の形式で付加する。一般的な方法では、この時に指定する関数名はウェブページ側ですでに定義されているコールバック用の関数の名前になる。
https://ja.wikipedia.org/wiki/JSONP
それでは以下、具体的にコードを書いてみましょう。
JSONPを理解するための段階的なコード
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONPその1</title>
<script>
function greeting(name) {
alert("Hello, " + name);
}
</script>
</head>
<body>
</body>
</html>
greetingという関数を理解してください。次にgreetingが実行されるようにしてみます。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONPその2</title>
<script>
function greeting(name) {
alert("Hello, " + name);
}
</script>
</head>
<body>
<script>
greeting("freshman");
</script>
</body>
</html>
上記をwebブラウザーで表示してください。「Hello, freshman」と表示されるはずです。この、
<script>
greeting("freshman");
</script>
の部分をscript要素のsrc属性に置き換える事で、JSONPの技術が完成します。書き換える前に、JSONPを返すサーバーサイドを実装します。今回はPHPで実装します。
適当なディレクトリーに移動して、index.phpという名前で次の内容のファイルを作成してください。
<?php
$name = $_GET['name'];
echo "greeting(\"$name\");";
同一ディレクトリーで次のコマンドを実行してください。
php -S localhost:8080
PHPのビルトインwebサーバーが起動します。webブラウザーで
http://localhost:8080?name=freshman
にアクセスしてみましょう。「greeting("freshman");」という文字列が表示されるはずです。それでは書き換えます。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONPその3</title>
<script>
function greeting(name) {
alert("Hello, " + name);
}
</script>
</head>
<body>
<script src="http://localhost:8080?name=freshman"></script>
</body>
</html>
実際にweb APIを使用する際、web APIに指定する変数は、画面の状態等によって動的に指定したい事がほとんどです。上記では静的に変数を指定(name=freshmanの部分)していますが、このままでは「ユーザーが画面で入力した名前に挨拶がしたい」というような要求は満たせません。
動的に生成したURLをsrc属性に指定する形で、document.createElementによってscript要素を動的に生成することで、これを解決します。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JSONPその4</title>
<script>
function greeting(name) {
alert("Hello, " + name);
}
</script>
</head>
<body>
<input type="text" id="name">
<input type="button" value="Call greeting" onclick="javascript:callJsonp();">
<script>
function callJsonp() {
var e = document.createElement('script');
e.type = 'text/javascript';
var name = document.getElementById("name").value;
e.src = "http://localhost:8080?name=" + name;
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(e, s);
}
</script>
</body>
</html>
いかがでしたでしょうか。
“あたりまえを創出し続ける”
それではまた、インターネットでお会いしましょう。