はじめに
Djangoでアプリ外部からPOSTされる処理を実装したので、テスト前にとりあえずcurlでも叩いて実施したところ、200(成功)でも500(エラー)でもなく403(閲覧禁止)が返ってくる事象があった。
しかし、GETでリクエストするとそのロジックは問題なく実行された。メソッド以外に違いがなくDjangoの仕様で沼ったのでその時の対処法をまとめてみた。
実際に書いてたソースのイメージ
以下のように仮に「test」って関数があって、GETかPOSTかによってレスポンス内容を変えて返す関数があり、その関数がurls.pyにルーティングされているとする。
from django.http import HttpResponse
def test(request):
if request.method == 'POST':
return HttpResponse('POST!!')
else:
return HttpResponse('GET!!')
from django.urls import path
from . import views
app_name = 'test'
urlpatterns = [
path('test', views.test, name ='test')
]
いざ実際にやってみると・・・
ちゃんと調べてみると
どうやら画面外からのリクエストなど、Djangoで発行したtokenがないPOSTのリクエストの場合にはPOSTができないらしい。
加えて念の為Django公式をみると「クロスサイトリクエストフォージェリ (CSRF) 対策」ってことで、アプリ側で独自に発行したtokenを持ってないとPOSTはエラーになるよってのがDjangoの仕様としてあるらしい。すごい。
対応したこと
「@csrf_exempt」をつけて対応した。
ただ、Django公式にも書いてある通りアプリ側で独自発行したtokenを無効にしているので、Djangoで管理しているtemplateからPOSTする時には使わず、またセッション管理している処理には実装しないなど無闇やらに使うものでもない気がする。
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt #追加
@csrf_exempt #追加
def test(request):
if request.method == 'POST':
return HttpResponse('POST!!')
else:
return HttpResponse('GET!!')
再度実行してみた
「@csrf_exempt」をつけて対応したところ、ちゃんと200が返ってきた。やったぜ。
最後に
DjangoがデフォルトでCSRFの脆弱性対応をしてくれてたことで沼ってたが、「@csrf_exempt」は無闇やたらに使ってはいけない奥の手な気がする。
気が向いたら他にいいやり方を模索するかも。