最近在开发测试工具平台以支持对于外部 Http 服务的接入,后端使用的框架是 Django,前端使用的框架是 React,前后端分离且域名不一致的情况下难免遇到了 “跨域” 问题,下面的文章就是记录这次问题发现和解决的全过程(最终的结果有点啼笑皆非)
阶段一问题:
前端发现所有的 post 请求,发起后变成了 get 请求,报错 403
排查解决:
1、post 请求变成 get 请求,第一反应就是怀疑是跨域请求的问题导致的,再加上自己即没有在服务层面解决跨域问题,有没有在 Ngnix 中进行处理跨域问题,OK,那就当做跨域问题去解决
2、跨域解决:
安装 django-cors-headers
pip3 install django-cors-headers
配置 settings.py 文件
INSTALLED_APPS = [
...
'corsheaders',
...
]
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware', # 注意顺序
...
)
#跨域增加忽略
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
CORS_ORIGIN_WHITELIST = (
'*'
)
CORS_ALLOW_METHODS = (
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
'VIEW',
)
CORS_ALLOW_HEADERS = (
'XMLHttpRequest',
'X_FILENAME',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
'Pragma',
)
然后启动服务,报错了 “ERRORS: ?: (corsheaders.E013) Origin '' in CORS_ORIGIN_WHITELIST is missing scheme or netloc HINT”
行吧,那就将
```CORS_ORIGIN_WHITELIST = ('') ```此行给注释掉
重启服务,正常运行,以为成功解决了
阶段二问题
运行服务倒是不报错了,部署到测试环境,发现全部接口请求都 404,以前 Ok 的 GET 请求也是 404 Network Error
[
继续排查解决:
1、从报错开始
报错:provisional headers are shown
打开控制台 Console 也有报错:
The 'Access-Control-Allow-Origin' header contains multiple values 'http://fe-test.yuceyi.com, http://fe-test.yuceyi.com'
包含了两个值,还是一样的,抓个包看一下,果然有两个 Access-Control-Allow-Origin
先看下第一个报错
挨个尝试了下,发现无效,然后怀疑是前端没有加 Content-Type 的请求头,让前端加上请求头后,发现依然没有解决问题
很是疑惑,接着查看服务器的请求日志发现,根本没有收到请求,此时已经开始怀疑是 Ngnix 配置的问题
2、
查看服务器上的 Nginx 配置文件,果不其然 cors 文件用以支持跨域,在 nginx.conf 中已经引入了该配置
当时为了快速将服务部署到机器上,copy 了一部分测试环境的 Nginx 配置,后面就忘记了,导致 Nginx 已经实现了跨域,自己又在代码层次实现了一遍,下面的图片,也是对该问题的解答
3、
OK,全部搞定,将代码里面关于跨域的代码注释掉,重新发布,发现还是不行
继续找解决方案:django 跨域请求时,为何将 post 请求转成了 get 请求?
各种寻找后,看到一个极老的帖子,也是同样的问题,其中有留言,说是因为静态资源文件的 url 和后端服务 url 重名了,比如后端服务的 url 是 /api/v1/take_case, 前端静态资源文件夹路径是/api/v1/take_case/ 这样就会出现上面的问题,在后端 url 中加上一个 / ,post 请求时也使用相应的 url 即可.
感觉已经找到了元凶,查看接口请求
果然,我在 django 的 urls 配置和给到前端的接口文档中,该接口是 /http_tools/project/create/
但是前端给到我的接口却是 /http_tools/project/create 坑啊~~~~
最终解决:
让前端在接口最后加上一个 / 后解决问题
所以各位日常工作中一定一定要注意看接口文档啊。。。。