Safari/iOS请求Django+Next.js项目接口返回403 其余浏览器运行正常
问题根因&解决方案
这个问题是Safari浏览器的特性和Django/DRF默认配置冲突导致的,按优先级排查解决即可:
1. 重定向丢认证头(最高概率)
Django默认开启APPEND_SLASH配置,当你请求的接口URL没有带末尾斜杠时(比如请求/api/get_categories而不是/api/get_categories/),Django会自动返回301重定向到带斜杠的地址。Chrome在重定向时会保留Authorization请求头,但Safari会在重定向时自动删除所有自定义请求头,导致重定向后的请求没有携带token,返回403。
- 解决方法1:前端请求时统一给所有接口URL加上末尾斜杠,避免触发重定向
- 解决方法2:在Django
settings.py中添加配置APPEND_SLASH = False,关闭自动补全斜杠逻辑,同步调整所有接口的URL定义即可。
2. OPTIONS预检请求被拦截
跨域请求下,Safari会主动对带自定义头(比如Authorization)的请求先发送OPTIONS预检请求,DRF默认的权限校验会要求OPTIONS请求也携带认证信息,直接返回403,导致后续实际请求不会发送。
- 解决方法:自定义DRF权限类,豁免OPTIONS请求的认证校验:
# 自定义权限类 from rest_framework.permissions import IsAuthenticated class ExemptOptionsPermission(IsAuthenticated): def has_permission(self, request, view): if request.method == "OPTIONS": return True return super().has_permission(request, view)
然后替换settings.py中的权限配置:
REST_FRAMEWORK = { # 其余原有配置保留 'DEFAULT_PERMISSION_CLASSES': ( '你的应用路径.ExemptOptionsPermission', ) }
3. 跨域配置不符合Safari要求
如果是前后端分离部署,要确保跨域配置适配Safari规则:
- 必须安装
django-cors-headers包处理跨域 - 不要用
*作为允许的源地址,要显式配置前端域名,示例配置:
# settings.py CORS_ALLOW_CREDENTIALS = True CORS_ALLOWED_ORIGINS = [ "https://你的前端域名.com", "http://localhost:8080", # 本地开发地址 ] CORS_ALLOW_HEADERS = [ # 其余默认头保留 "authorization", "content-type", ]
验证方法
打开Safari开发者工具的「网络」面板,勾选「保留日志」选项,重新发起请求,就能看到完整的请求链路:如果有301重定向就是问题1,如果OPTIONS请求返回403就是问题2。
内容的提问来源于stack exchange,提问作者Diego Oquendo
相关产品推荐
相关产品推荐

