能否从JavaScript向Django API发送CSRF Cookie-Token?跨域POST遇403错误
问题描述
我有一个基于Svelte框架开发、Netlify部署的SAP应用,业务逻辑和数据处理依赖Django后端。之前只用GET请求一切正常,但现在需要上传文件并使用POST请求,发送POST请求到Django时收到403错误,错误日志如下:
WARNING:django.security.csrf:Forbidden (Origin checking failed - http://localhost:8888 does not match any trusted origins.): /test-put/
我已经处理了CORS相关配置,但还是遇到这个问题。
前端调用代码(JavaScript)
async function sendDataToAPI(payload) { let endpoint = 'http://192.168.4.28:8000/test-put/' const form_data = new FormData(); form_data.append("payload", payload); await fetch(endpoint, { credentials: "same-origin", method: "POST", body: JSON.stringify({ data: payload, }), headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', "X-CSRFToken": getCookie("csrftoken"), }, }) .then((response) => response.json()) .then((result) => { console.log("Success:", result); }) .catch((error) => { console.error("Error:", error); }); } function getCookie(name) { let cookieValue = null; if (document.cookie && document.cookie !== '') { const cookies = document.cookie.split(';'); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; }
Django 路由配置(urls.py)
path('test-put/', views.TestPut.as_view()),
Django 视图代码(views.py)
class TestPut(View): def put(self, request): return {}
核心疑问
由于发起请求的页面不是Django模板,这种场景下实现POST请求是否可行?该如何解决这个403错误?
解决方案
1. 解决跨域信任源问题
错误日志明确提示Origin checking failed,说明Django未将前端域名加入可信源。在Django的settings.py中添加配置:
ALLOWED_HOSTS = ['192.168.4.28', 'localhost', '你的Netlify线上域名'] CSRF_TRUSTED_ORIGINS = [ 'http://localhost:8888', 'https://你的Netlify线上域名', 'http://192.168.4.28:8000' ]
注意:Django 3.2及以上版本必须通过CSRF_TRUSTED_ORIGINS配置跨域可信源,仅靠CORS插件无法解决CSRF的源校验问题。
2. 修正前后端请求/响应匹配问题
- 前端代码中创建了
FormData但未实际使用,若要上传文件,应直接将FormData作为请求体,且不要手动设置Content-Type(浏览器会自动添加正确的边界标识)。 - 跨域请求需携带Cookie(包括CSRF Token),因此
credentials需设为"include"而非"same-origin"。 - 原Django视图仅实现了
put方法,但前端发送的是POST请求,会导致405方法不允许,需修改视图支持POST:
修正后的前端代码
async function sendDataToAPI(payload, file) { let endpoint = 'http://192.168.4.28:8000/test-put/' const form_data = new FormData(); form_data.append("payload", payload); if (file) { form_data.append("file", file); // 添加待上传的文件 } await fetch(endpoint, { credentials: "include", method: "POST", body: form_data, headers: { 'Accept': 'application/json', "X-CSRFToken": getCookie("csrftoken"), }, }) .then((response) => response.json()) .then((result) => { console.log("Success:", result); }) .catch((error) => { console.error("Error:", error); }); }
修正后的Django视图
from django.http import JsonResponse class TestPut(View): def post(self, request): # 从FormData中获取数据 payload = request.POST.get('payload') uploaded_file = request.FILES.get('file') # 编写你的业务处理逻辑 return JsonResponse({'status': 'success', 'message': '数据接收成功'})
3. 非Django模板页面的CSRF Token获取方案
因为前端不是Django模板,无法使用{% csrf_token %},可通过两种方式获取Token:
- 方案一:新增Django接口返回Token
# urls.py path('get-csrf-token/', views.get_csrf_token), # views.py from django.middleware.csrf import get_token from django.http import JsonResponse def get_csrf_token(request): return JsonResponse({'csrfToken': get_token(request)})
前端先调用该接口获取Token,再在POST请求中携带。
- 方案二:确保Cookie正常传递
在Django的settings.py中开启CORS允许携带Cookie:
CORS_ALLOW_CREDENTIALS = True
这样前端的getCookie函数就能从Django设置的Cookie中拿到CSRF Token。
4. 确认CORS配置完整性
确保django-cors-headers的配置正确:
INSTALLED_APPS = [ ... 'corsheaders', ... ] MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', ... ] CORS_ALLOWED_ORIGINS = [ 'http://localhost:8888', 'https://你的Netlify线上域名', ]
内容的提问来源于stack exchange,提问作者Psionman
相关产品推荐
相关产品推荐

