概要
※ 調査中。未解決です。暫定的な方法で解決しています。
フロント側からaxios.post
でDjango(REST framework)にPOSTリクエストを送ると、Response to preflight request doesn't pass access control となってしまう。ajaxで送ってみたところ、正常にレスポンスが返ってきました。
色々試してみた結果、おそらくaxiosかdjango-cors-headerの使い方が悪そうです。
環境
- Django 3.0.3
- djangorestframework 3.11.0
- django-cors-header 3.2.1
- heroku
経緯
Django REST frameworkで作ったAPIを、Vue.jsで作った画面から呼び出して使うアプリケーションを作ろうとしておりました。某イベント開催に向け、便利なLINEアプリを作るためです。
Django REST frameworkでviewの作成
本家のチュートリアルをChapter3 くらいまで呼んで、簡単なviewを作成しました。
そして、ブラウザからAPIが想定通り動作することを確認。
django-cors-headerでCORSの設定
フロント側にVue.jsを使うため、CORSを許可します。
django-cors-headerで以下のように設定。
これによって、GETリクエストが通るようになりました。
しかし、POSTの時に送られるpreflight requestが正常に帰ってこない...
# 変更部のみ抜粋
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app.apps.AppConfig',
'rest_framework',
'corsheaders' # 追加
]
MIDDLEWARE = [
'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',
'corsheaders.middleware.CorsMiddleware', # 追加
'django.middleware.common.CommonMiddleware', # 追加
]
CORS_ORIGIN_WHITELIST = [
'http://localhost:3000', # フロントのサーバー
]
調査
preflight requestの行き先
preflight requestは、optionsで飛ぶようなので、APIサーバ側でoptionsリクエストが受け取れないようになっているのかもしれません。
そこで当該viewにoptionsを処理する部分を明示的に作り、Pycharm のデバッガでOPTIONSリクエストの行き先を確認してみます。
from rest_framework.views import APIView
# --- 中略 ---
class ClassBasedView(APIView):
def post(self, request, format=None):
# 処理
def options(self, request, format=None):
# 処理
viewsのaxios.post
からのリクエストは、options
の部分には到達していない様子。
しかし、curlでリクエスト送ると、options
に到達します。
また、viewを関数ベースのものに変えてみても状況は同じでした。
ということは、django-cors-headerの使い方がどこか間違っているのでしょうか。。。
axiosの調査
一方で、試しにajaxでpostリクエストを送ってみると、正常にレスポンスが帰ってきました。
Django側のログを見てみると、OPTIONSリクエストは受け取っていない模様。
つまり、preflight requestの受け渡しが上手くいっていないようです。
// headerの設定
axios.defaults.headers.post['Access-Control-Allow-Origin'] = 'http://localhost:3000';
axios.defaults.baseURL = 'http://localhost:3000';
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8';
axios.post(url, params) // こっちはだめ
$.ajax({url:url, type:'POST', data: params}) // こちらはリクエスト成功
まとめと今後
ajaxでデータ取得できたので、当面はajax使って開発を進めることにしました 。
(コロナショックでアプリ自体が不要になってしまいました...)
今後は、以下を調べてみようと思います。
- Djangoでpreflight requestがどう処理されるのか(django-cors-header の詳細な使い方)
- axiosでpreflight requestがどうやって送られるのか