UTALI

みんなの役に立つ情報をどんどん公開していきます

【Python3】djangoでajaxのクロスドメイン通信(CORS)が可能になるよう設定する

f:id:mochizuki_p:20170627184635p:plain

ブラウザでの別ドメインへの非同期通信は、非同期通信のリクエストを受けるサーバー側で、特殊なヘッダを追加する必要があります。

akiniwa.hatenablog.jp

このページのように直接ヘッダを属性値を追加する方法でも、非同期通信を実行することは可能ですが、 複数のエンドポイントを設定する場合に、このように個別の設定を行うのでは非効率です。

直接ヘッダを変更しても構わないが・・

Node.jsでのExpressやRuby on Railsなど、Webアプリケーションのためのフレームワークでは、複数のエンドポイントに対して共通の設定を適応する場合に、ミドルウェアと呼ばれるライブラリを使用するのが一般的です。

Djangoのクロスドメイン通信を設定するために一般的に使用されているミドルウェアがあります。

django-cors-headersを使う

それがdjango-cors-headersです。

github.com

このミドルウェアでは、

  • クロスオリジン通信を許可するドメインを複数指定
  • 正規表現でのドメイン指定
  • 正規表現でクロスオリジン通信を許可するパスの指定
  • クロスオリジン通信を許可するメソッドの指定
*クロスオリジン通信で許可する非標準ヘッダの設定

などを一括して設定することが可能になります。

その最大の利点は、クロスオリジン通信の設定をsettting.pyで集約して行うことが可能なのが第一です。

それでは本題に入ります。

基本的な設定


Python3の場合を説明します。Python2の場合も同じです。

pip3をpipに変えるだけで大丈夫なはずです。

最初にライブラリを導入

pip3 install django-cors-headers

Djangoアプリのsettings.pyを編集します。

INSTALLED_APPS に “corsheaders"を追加します。

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

次にMIDDLEWARE に ‘corsheaders.middleware.CorsMiddleware’ を追加します。

このとき注意すべきなのは、できるだけリストの上側に追加するということです。このミドルウェアはHTTPリスポンスヘッダを変更するように動作するので、これはリスポンスを生成するミドルウェアより先に動作させるようにしたいからです。

例えば、'django.middleware.common.CommonMiddleware' より下に設定すると、このミドルウェアがヘッダを変更する前にリスポンスを返してしまい、エラーが発生します。

MIDDLEWARE = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    ...
]

設定

以上の設定項目を追加したら、その下側に以下の設定を行います

全てのリクエストを受け付けたい場合

CORS_ORIGIN_ALLOW_ALLをTrueに変更します。

しかし、これはセキュリティの関係から好ましくありません。できるだけ、CORSを許可するドメインは限定すべきです。

CORS_ORIGIN_ALLOW_ALL = True

クロスオリジンを許可するドメインを限定する

CORS_ORIGIN_WHITELIST クロスオリジン通信を許可するドメインをリスト形式で指定します。この場合はサブドメインを必ず含めるようにしてください。

ここの設定はワイルドカードなどは利用できないようです。

CORS_ORIGIN_WHITELIST = (
    'google.com',
    'www.utali.io',
    'utali.io'
)

特定のドメインのサブドメインを全て許可したい場合などや、特定のパターンでクロスドメイン通信を許可したい場合は、CORS_ORIGIN_REGEX_WHITELISTを指定します。

Python3での標準的な正規表現の記法に準じて、リクエストを許可できます。

以下の例ではセキュリティのためにhttpsのみに対応しつつ、utali.ioの全てのサブドメインからの通信を許可するようにします。

CORS_ORIGIN_REGEX_WHITELIST = (
    r'^(https://)?(\w+\.)?utali\.io$',
)

特定のパスのみ、クロスオリジン通信を許可する

APIを提供するパスのみクロスオリジンを提供したいという要求もあると思います。 その場合は、CORS_URLS_REGEX を指定することで特定のパスのみをCORSに対応させることが可能になります。

当然ですが、ドメインの部分は含みません。

以下の例では、/json/3514aabab353や/json/user/hogehogeなど、/json 以下のパスのみをクロスドメイン通信に対応させることができます。

CORS_URLS_REGEX = r'^/json/.*$'

特定のメソッドのみ、クロスオリジン通信を許可する

CORS_ALLOW_METHODSを使います。

以下の例ではGET, POST, PUT, OPTIONSのみを許可しています。

CORS_ALLOW_METHODS = (

    'GET',
    'OPTIONS',
    'POST',
    'PUT',
)

非標準のヘッダを許可する

CORSでは、セキュリティのために特別な許可を与えないと、非標準のヘッダを追加することができません。

これを設定するには、

CORS_ALLOW_HEADERS を設定します。

CORS_ALLOW_HEADERS = (
    'accept',
    'accept-encoding',
    'x-csrftoken',
    'x-requested-with',
)

Herokuで利用する場合の注意点、

Herokuで利用する場合はrequirements.txtに追記することを忘れないようにしてください。

pip3 freeze > requirements.txt

つい忘れがちなので、注意