目的
- Ajaxリクエスト用のアクションなので、Ajaxリクエストの場合のみレスポンスしたい。
- たとえば、WebブラウザからURL直接アクセスされたり、curlとかでスクレイピングされた場合はレスポンスを返したくない。
対応方針
- AjaxはすなわちJavaScriptでの通信で、XMLHTTPRequest(XHR)という約束事に沿って実行されます。
- この際にリクエストヘッダに X-Requested-With ヘッダがセットされます。
- jQueryなどでは(おそらくセキュリティ的な理由から)クロスドメインアクセスの場合はこのヘッダがセットされなかったりします。
- 判定方法としては、"リクエストヘッダにX-Requested-WithがあればAjax、なければ非Ajax"とします。
対応方針(続き)
- Djangoにはこの判定メソッドが備わっています。 (see:HttpRequest.is_ajax)
- リクエストがAjaxだったらJSON、そうでなければhtmlを返すような場合はそれぞれ判定すれば良さそうです。
- ただ、今回はAjaxリクエストでなければエラーにしたいので、デコレーターにしてみます。
コード
utils/decorators.py
def ajax_required(ret_unexcepted):
"""
Decorator for determing whether the request is Ajax, in Django-views.
e.g.) in views.py
from django.http import HttpResponseBadRequest
from utils.decorators import ajax_required
@ajax_requirxed(HttpResponseBadRequest())
def index(request):
pass
"""
def _ajax_required(func):
def wrapper(request, *args, **kwargs):
if not request.is_ajax():
return ret_unexcepted
return func(request, *args, **kwargs)
return wrapper
return _ajax_required
具体的には
コメントどおりなのですが、具体的には。
utils/decorators.py に上記コードを記述
app/views.pyに下記記述(Ajaxリクエストでない場合はBadRequestを返す)
app/views.py
from django.http import HttpResponseBadRequest
from utils.decorators import ajax_required
@ajax_required(HttpResponseBadRequest())
def index(request):
# any code
確認
- 対応前(正常にレスポンスしている)
$ curl --head http://localhost:5000/app/index/
HTTP/1.1 200 OK
...
- @ajax_required記述後(エラーレスポンスに変化している)
$ curl --head http://localhost:5000/app/index/
HTTP/1.1 400 Bad Request
...