XHR専用reverse proxy
XHR(XMLHttpRequest)はクロスドメインで使えないという制約があります(セキュリティのため)。簡単に言うと、JavaScriptだけで、あるサイトから情報をAJAX的に取得、別のサイトから情報をAJAX的に取得、のようなことができません。
こういうこと(いわゆるマッシュアップ)をしたい場合、サービス側の支援があればJSONP(#1)が使えますが、普通はサーバサイドで情報を混ぜ合わせます。
http://ajaxpatterns.org/Cross-Domain_Proxy では、仰々しく書いてありますが、単発のHTTPリクエストを横流しするだけなら、簡単なreverse proxyでも事足ります。仲介サーバが何もしないので、JavaScriptががんばる必要がありますが、JavaScriptは頑張り屋さんなので、問題ありません。
Apacheのmod_rewriteであれば次のような設定をするイメージです(#2)。
RewriteEngine On RewriteRule /p/(.*)/(.*) http://$1/$2 [P]
AJAXを使うJavaScriptのコードは次のようになります(prototype.js前提)。これでjalanのWeb APIを叩けます。
new Ajax.Request( "/p/jws.jalan.net/APICommon/OnsenSearch/V1/", ...(パラメータ等は省略)
AirOneは元々reverse proxyっぽい機能を持っていたので、上のような"/p/ホスト名/パス"のリクエストをreverse proxyする機能を実装しました(#3)。
温泉検索がJavaScriptだけで書けます。次のHTMLファイルをAirOneのデータディレクトリの下に置きます。ファイル名がonsen.htmlだとすると、Webブラウザで http://localhost:6809/airuser/onsen.html にアクセスすると使えます。ただし、HTML中の"APIキー"の部分は自分で取得して、自分で値を書いてください(#4)。
北海道と青森しか検索できません。理由はこれ以上暑い場所が嫌い、というわけではなく、単にHTMLを書くのが面倒だからです。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html lang="ja">
<head>
<title>Title</title>
<script type="text/javascript" src="/airdir/script47100/prototype.js"></script>
<script type="text/javascript">
<!--
function showResult(xml) {
var strarr = new Array();
var num = xml.getElementsByTagName('NumberOfResults')[0].firstChild.nodeValue;
strarr.push('<h2>見つかった数: ' + num + '</h2>');
var results = xml.getElementsByTagName('Onsen');
strarr.push('<table>');
for (var i = 0, num = results.length; i < num; i++) {
var name = results[i].getElementsByTagName('OnsenName')[0].firstChild.nodeValue;
var location = results[i].getElementsByTagName('OnsenAddress')[0].firstChild.nodeValue;
var nature = results[i].getElementsByTagName('NatureOfOnsen')[0].firstChild.nodeValue;
strarr.push('<tr><td>' + name + '</td><td>' + location + '</td><td>' + nature + '</td></tr>');
}
strarr.push('</table>');
$('result').innerHTML = strarr.join('');
}
function getit() {
var key = Form.Element.getValue('key');
var pref = Form.Element.getValue('pref');
var query = Form.Element.getValue('query');
new Ajax.Request(
"/p/jws.jalan.net/APICommon/OnsenSearch/V1/",
{
method: 'get',
parameters: 'key=' + key + '&pref=' + pref + '&onsen_q=' + query,
onSuccess: function(res) {
showResult(res.responseXML);
}
}
);
}
//-->
</script>
</head>
<body>
<input type="hidden" id="key" value="APIキー"/>
<select id="pref">
<option value="010000">北海道</option>
<option value="020000">青森</option>
</select>
<select id="query">
<option value="1">単純</option>
<option value="2">アルカリ</option>
</select>
<a href="javascript:getit()">温泉検索</a>
<div id="result"/>
</body>
</html>
(#1)JSONPを利用した仕組みを知った時は、酔狂なことを考えるものだと感心しました。リクエスト時に(パラメータで)関数名を渡して、関数呼び出しの形式の文字列をもらいます。この時、関数呼び出しの引数にJSON形式のデータがあるので、evalすることでリクエスト側が自分の関数でデータを受け取れます。evalができて、データの文字列へのシリアライズが容易で、かつその文字列表現をそのまま関数の引数に渡せる言語であることが必要です。なんか、この言語的特性、Lispを想起させます。
(#2)この設定でインターネットに公開するのは止めた方が身のためです(reverse proxy自体が公開する性格のものではありません)。
(#3)リクエスト行しか見ない簡易実装なので、redirectやHTTP認証などがあると使えません。
(#4)APIキーの扱いや存在意義が良く分かっていません。どうせダミーのメールアドレスで取得したAPIキーなので、さらしても何も痛みませんが、サービス提供者(今の場合、じゃらん)が、APIキーで何を守ろうとしているのかが分からないので、軽率な行動が取れません。困ったものです。APIキーが無ければ、JavaScriptアプリをどんどんAirOneといっしょに配布できるのですが。
- Category(s)
- カテゴリなし
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/inoue/reverse-proxy-for-xhr/tbping
- ハングリーさが足りない
- ¦
- Main
- ¦
- 自由意志