Django 5与Nuxt3跨域请求Cookie无法携带问题求助
问题核心
跨域场景下,后端登录接口返回的sessionid和csrftoken已在响应头的Set-Cookie中,但前端后续请求未携带任何Cookie,Postman测试正常但前端失效,本质是后端Cookie配置与前端请求规则不匹配。
后端Django配置修正
1. 统一Cookie跨域规则
浏览器强制要求:当SameSite=None时,Cookie必须设置Secure=True(仅HTTPS传输),之前的SESSION_COOKIE_SECURE=False是错误配置,会被浏览器拦截。同时需同步CSRF Cookie的配置:
# settings.py CORS_ALLOWED_ORIGINS = ['http://localhost:3000'] # 仅允许前端域名,移除重复的CORS_ORIGIN_WHITELIST CORS_ALLOW_CREDENTIALS = True # Session Cookie配置 SESSION_COOKIE_SAMESITE = 'None' SESSION_COOKIE_SECURE = True # 必须与SameSite=None配合 SESSION_COOKIE_HTTPONLY = True # 保持开启,防止XSS # CSRF Cookie配置(需与Session Cookie对齐) CSRF_COOKIE_SAMESITE = 'None' CSRF_COOKIE_SECURE = True CSRF_COOKIE_HTTPONLY = False # 设为False,让前端能读取CSRF Token # 允许前端携带CSRF请求头 CORS_ALLOW_HEADERS = [ 'Accept', 'Accept-Encoding', 'Authorization', 'Content-Type', 'Cookie', 'X-CSRFToken', # 新增,用于前端传递CSRF Token ]
2. 简化登录视图逻辑
无需手动返回sessionid,Django会自动设置Session Cookie,手动返回反而可能干扰前端逻辑:
@action(detail=False, methods=['POST']) def login(self, request): username = request.data['username'] password = request.data['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return Response({'message': "Logged in!"}) else: return Response( {'message': "Invalid credentials provided"}, status=status.HTTP_400_BAD_REQUEST )
前端Nuxt 3请求配置
1. 强制携带凭证
所有跨域请求必须设置credentials: 'include',否则浏览器不会携带Cookie:
2. 自动携带CSRF Token
前端需从Cookie中读取csrftoken,并放到X-CSRFToken请求头中,供Django验证。可以封装统一的请求工具:
// composables/useApi.js export const useApi = () => { // 从Cookie中提取CSRF Token const getCsrfToken = () => { const cookieList = document.cookie.split('; ') const csrfItem = cookieList.find(item => item.startsWith('csrftoken=')) return csrfItem ? csrfItem.split('=')[1] : '' } // 封装带认证的请求 const fetchWithAuth = async (url, options = {}) => { const defaultOptions = { credentials: 'include', // 关键:跨域携带Cookie headers: { 'Content-Type': 'application/json', 'X-CSRFToken': getCsrfToken(), // 自动带上CSRF Token ...options.headers }, ...options } return await $fetch(url, defaultOptions) } return { fetchWithAuth } }
3. 登录请求示例
// 页面组件中使用 const { fetchWithAuth } = useApi() const handleLogin = async () => { try { const res = await fetchWithAuth('/api/login/', { method: 'POST', body: JSON.stringify({ username: 'yourname', password: 'yourpwd' }) }) console.log(res.message) } catch (err) { console.error(err.response._data.message) } }
本地开发适配
如果本地不想用HTTPS,可以临时调整Cookie规则(仅开发环境使用,生产必须用HTTPS):
# settings.py 仅开发环境 SESSION_COOKIE_SAMESITE = 'Lax' SESSION_COOKIE_SECURE = False CSRF_COOKIE_SAMESITE = 'Lax' CSRF_COOKIE_SECURE = False
同时确保前后端域名完全一致:比如后端用localhost:8000,前端必须用localhost:3000,不能混用localhost和127.0.0.1(浏览器视为不同域名)。
内容的提问来源于stack exchange,提问作者user25016662
相关产品推荐
相关产品推荐

