この記事は、 岩手大学 Advent Calendar 2020 の24日目の記事です。
はじめに
個人開発でDjangoを使ったAPIをつくるときがありました。
そのとき、APIの実装でCORS問題にぶち当たり、CORSの対応をする必要がありました。
Djangoには django-cors-headers というものがあります。しかし、django-cors-headersを使って実装をしてみましたが、どうもAccess-Control-Allow-Origin
がうまく指定できず、他のサイトからでもリクエストを送れるようになってしまっていました。
そこで、Djangoのミドルウェアを作成しCORS対応をしましたのでご紹介します。
Django初心者なので、間違いなどがありましたらご指摘していただけると勉強になります。
実装
実装は以下のようになりました。
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class CustomCorsMiddleware(MiddlewareMixin):
def process_request(self, request):
if request.method == 'OPTIONS':
response = HttpResponse()
response['Access-Control-Allow-Origin'] = 'http://localhost:3000' # クライアントのオリジン
response['Access-Control-Allow-Headers'] = ', '.join([ # 許可するHeaderを追加
'Content-Type',
])
response['Access-Control-Allow-Methods'] = ', '.join([ # 許可するリクエストメソッドを追加
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
])
return response
else:
return None
def process_response(self, request, response):
response['Access-Control-Allow-Origin'] = 'http://localhost:3000' # レスポンスを読み取ることができるオリジン
response['Content-Type'] = 'application/json' # レスポンスタイプ
return response
process_request
メソッドは、リクエストが来たときに実行され、None
が返り値の場合はルーティングされているview
が実行されます。
リクエスト
↓
process_request が実行 → 返り値がある場合はその返り値を返す
↓
返り値が None の場合は、リクエストのルーティングに対応する`view`が実行される
上記のコードでは、プリフライトリクエストに備えて、OPTIONS
メソッドの場合は、許可するオリジン・ヘッダー・リクエストメソッドをヘッダーに付与したレスポンスを返すようにしています。
次に、process_response
メソッドは、レスポンスをするときの最後に実行されます。
view を実行
↓
process_request が view から返されたレスポンスを受け取り、レスポンスに処理を行う
↓
レスポンス
上記のコードでは、CORSでよく見る
Access to XMLHttpRequest at 'http://locahost:8000' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
のためにレスポンスを読み取ることができるオリジンを指定し、またレスポンスタイプにapplication/json
を指定しています。
あとは、このカスタムミドルウェアをsettings.py
に追加してあげれば完了です。
MIDDLEWARE = [
'custom_middlewares.custom_cors_middleware.CustomCorsMiddleware', # 追加
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
おわりに
Djangoを触ってみて思ったのは、日本語のドキュメントが少ないことです。
英語のドキュメントでも日本語のように読めると苦労が減るのかもしれませんね。