GAE/Python で JSONP
Sever 2015. 3. 27. 16:33http://99blues.dyndns.org/blog/2011/07/gae_jsonp/
크로스도메인 해결 방법으로 jsonp 사용
Google App Engine/Python 上に JSONPのサービスを実装してみます。
また、クライアントからサーバへののJSONP呼び出しは jQueryを使用します。
サンプルを作ってみる
JSONPの概要説明はネットで検索すればいろいろ見つかるので省略し、さっさと実装していきます。
簡単な実装
まずは、固定値を返す最小限の実装を試します。
サーバー側(GAE/Python)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | # -*- coding: utf-8 -*- import simplejson import datetime from google.appengine.ext import webapp from google.appengine.ext.webapp.util import run_wsgi_app class JSONPHandler(webapp.RequestHandler): def get( self ): # クライアントに返すデータ data = { 'id' : self .request.get( 'id' ), 'name' : 'your name' } # 辞書形式をJSON形式に変換 json = simplejson.dumps(data, ensure_ascii = False ) # callback でラップ callback = self .request.get( 'callback' ) if callback: json = '%s(%s)' % (callback, json) # コンテンツ形式は javascript self .response.headers[ 'Content-Type' ] = 'application/javascript; charset=utf-8' # データの有効期限を設定 (ここは任意) expires_date = datetime.datetime.now() + datetime.timedelta(minutes = 10 ) self .response.headers[ "Expires" ] = expires_date.strftime( "%a, %d %b %Y %H:%M:00 GMT" ) self .response.headers[ "Cache-Control" ] = "public, max-age=%s" % ( 60 * 10 ) # 応答を返す self .response.out.write(json) application = webapp.WSGIApplication([( '/get_jsonp' , JSONPHandler), ], debug = True ) def main(): run_wsgi_app(application) if __name__ = = "__main__" : main() |
(使い方)
- GAE/Pythonのプロジェクトを作成し、このコードを組み込みます。
- SDK付属の開発用サーバを使って、プロジェクトを実行します。
(補足)
- 11~12行目の辞書データを変更すれば、違うデータを返すことが出来ます。
- 18~20行目の処理が、JSONPを返すための肝です。 これをしないと、ただの JSONです。
クライアント側(HTML+jQuery)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <!DOCTYPE html> < html > < head > < script type = "text/javascript" src = "http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></ script > </ head > < body > < p >id:< span id = "id" style = "color:red" ></ span ></ p > < p >name:< span id = "name" style = "color:blue" ></ span ></ p > < script type = "text/javascript" > $(function(){ $.getJSON("http://localhost:8080/get_jsonp?id=hoge&callback=?", function(data){ $('#id').text(data['id']); $('#name').text(data['name']); } ); }); </ script > </ body > </ html > |
(使い方)
- HTMLファイルをローカルフォルダに保存します。
- 必要ならサーバのURLを修正します。 (13行目)
接続先がローカル環境の開発用サーバであれば、修正不要です。
- ブラウザでHTMLファイルを開きます。
JSONPが成功すれば、ブラウザに次のように表示されます。
(補足)
- 13~18行目でJSONPリクエストを処理しています。
- jQueryの getJSON()関数でJSONPリクエストを処理します。
- サーバからレスポンスが返ってくると、コールバック関数:function() が実行されます。
サーバからのデータ(JSON形式)はコールバック関数の引数(ここでは変数:data)に渡されます。
- jQueryの getJSON()関数でJSONPリクエストを処理します。
モデル(エンティティ)をJSONP
次はGAEらしく、モデルクラス(エンティティ)をJSONP形式にして返してみます。
サーバー側(GAE/Python)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | # -*- coding: utf-8 -*- import simplejson import datetime from google.appengine.ext import webapp from google.appengine.ext.webapp.util import run_wsgi_app from google.appengine.ext import db # 今回使用するモデル class Person(db.Model): name = db.StringProperty(required = True ) age = db.IntegerProperty(required = True ) class EntityHandler(webapp.RequestHandler): def get( self ): # モデルのインスタンス person = Person(name = 'hoge hoge' , age = 99 ) # モデルをPythonの辞書形式に変換 data = dict (name = person.name, age = person.age) # 後は最初のサンプルと同じ json = simplejson.dumps(data, ensure_ascii = False ) callback = self .request.get( 'callback' ) if callback: json = '%s(%s)' % (callback, json) self .response.headers[ 'Content-Type' ] = 'application/javascript; charset=utf-8' expires_date = datetime.datetime.now() + datetime.timedelta(minutes = 10 ) self .response.headers[ "Expires" ] = expires_date.strftime( "%a, %d %b %Y %H:%M:00 GMT" ) self .response.headers[ "Cache-Control" ] = "public, max-age=%s" % ( 60 * 10 ) self .response.out.write(json) application = webapp.WSGIApplication([( '/get_entity' , EntityHandler), ], debug = True ) def main(): run_wsgi_app(application) if __name__ = = "__main__" : main() |
(補足)
- モデルクラスを辞書形式に変換してしまえば、後は最初のサンプルと同じ手順で処理出来ます。
(変換例)
クライアント側(HTML+JQuery)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <!DOCTYPE html> < html > < head > < script type = "text/javascript" src = "http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" ></ script > </ head > < body > < p >name:< span id = "name" style = "color:red" ></ span ></ p > < p >age:< span id = "age" style = "color:blue" ></ span ></ p > < script type = "text/javascript" > $(function(){ $.getJSON("http://localhost:8080/get_entity?callback=?", function(data){ $('#name').text(data['name']); $('#age').text(data['age']); } ); }); </ script > </ body > </ html > |
最初の例とあまり変わらないので、説明は省略します。
JSONPではどんなデータが流れているか?
JSONPを使う時、クライアント・サーバ間でどんな内容の通信が行われているのでしょうか?
ブラウザ(Chrome)のデバッグ機能を使って、通信内容を見てみます。
リクエストURI
クライアント側のJSONPリクエストを発行するコードは次のようになってました。
実際にサーバに送信するときのリクエストURIは次のようになっています。
サーバからのレスポンス
単なるJSONデータではなく、関数呼び出しでラッピングされていることが分かります。
最後に
JSONPとか、クロスドメインと聞くと何やら難しげに思えますが、実際はサーバ側、クライアント側共、実装方法はそれほど難しくありません。
クロスドメインが使えるようになれば、システム構成の自由度が上がり便利です。
Comments are closed.
'Sever' 카테고리의 다른 글
a href onclick parameter 전달 방법 (0) | 2015.04.29 |
---|---|
footer 영역 항상 하단에 고정하기 (0) | 2015.04.27 |
[파이썬 Python] 날짜, 시간값의 연산법, 시간차이 구하기(몇시간, 몇분 전/후 등) (0) | 2015.04.07 |
Using Google Cloud SQL (0) | 2015.04.07 |
How to escape < and > inside <pre> tags (0) | 2015.04.06 |