在Django REST框架中,预检请求(preflight request)无法正常工作
总结
正在调查中。尚未解决。我们通过临时措施解决了问题。
当我使用axios.post从前端向Django(REST框架)发送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
事件的过程
我正试图制作一个应用程序,调用从Vue.js创建的页面上的Django REST框架创建的API,以便在某个活动举办之前创建一个方便使用的LINE应用程序。
使用Django REST框架创建视图。
我已经阅读了本家教程直到第三章左右,并创建了一个简单的视图。然后,我从浏览器确认了API的预期操作。
使用django-cors-header进行CORS设置。
为了在前端使用Vue.js,允许跨域资源共享(CORS)。
django-cors-header进行如下配置。
这样,GET请求会成功通过。
然而,发送的预检请求在POST时却无法正常返回…
# 変更部のみ抜粋
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)使用了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`。
此外,即使将视图更改为函数式的形式,情况仍然相同。
这意味着,django-cors-header的使用方法可能有些错误吗?
axios 进行的调查
在尝试使用ajax发送post请求的同时,我收到了正常的响应。
查看Django端的日志后发现,似乎没有接收到OPTIONS请求。
换句话说,预检请求的传递似乎出现了问题。
// 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がどうやって送られるのか