Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

posted at

updated at

Organization

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

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?