LoginSignup
3
3

More than 3 years have passed since last update.

DjangoでCORSカスタムミドルウェアをつくった

Last updated at Posted at 2020-12-23

この記事は、 岩手大学 Advent Calendar 2020 の24日目の記事です。

はじめに

個人開発でDjangoを使ったAPIをつくるときがありました。
そのとき、APIの実装でCORS問題にぶち当たり、CORSの対応をする必要がありました。

Djangoには django-cors-headers というものがあります。しかし、django-cors-headersを使って実装をしてみましたが、どうもAccess-Control-Allow-Originがうまく指定できず、他のサイトからでもリクエストを送れるようになってしまっていました。
そこで、Djangoのミドルウェアを作成しCORS対応をしましたのでご紹介します。

Django初心者なので、間違いなどがありましたらご指摘していただけると勉強になります。

実装

実装は以下のようになりました。

custom_middlewares/custom_cors_middleware.py
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に追加してあげれば完了です。

your_application_name/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を触ってみて思ったのは、日本語のドキュメントが少ないことです。
英語のドキュメントでも日本語のように読めると苦労が減るのかもしれませんね。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3