当你遇到跨域问题,松解不要立刻就选择复制去尝试。决跨请详细看完这篇文章再处理 。域问我相信它能帮到你
。题简
分析前准备:
前端网站地址:http://localhost:8080服务端网址:http://localhost:59200首先保证服务端是松解没有处理跨域的
,其次,决跨先用postman测试服务端接口是域问正常的
图片
当网站8080去访问服务端接口时,就产生了跨域问题
,题简那么如何解决?松解接下来我把跨域遇到的各种情况都列举出来并通过nginx代理的方式解决(后台也是一样的
,云计算只要你理解的决跨原理)。
跨域主要涉及4个响应头:
Access-Control-Allow-Origin 用于设置允许跨域请求源地址 (预检请求和正式请求在跨域时候都会验证)Access-Control-Allow-Headers 跨域允许携带的域问特殊头信息字段 (只在预检请求验证)Access-Control-Allow-Methods 跨域允许的请求方法或者说HTTP动词 (只在预检请求验证)Access-Control-Allow-Credentials 是否允许跨域使用cookies,如果要跨域使用cookies ,题简可以添加上此请求响应头,松解值设为true(设置或者不设置,决跨都不会影响请求发送,域问只会影响在跨域时候是否要携带cookies,但是如果设置
,预检请求和正式请求都需要设置)
。不过不建议跨域使用(项目中用到过
,源码库不过不稳定
,有些浏览器带不过去),除非必要,因为有很多方案可以代替。网上很多文章都是告诉你直接Nginx添加这几个响应头信息就能解决跨域 ,当然大部分情况是能解决,但是我相信还是有很多情况 ,明明配置上了 ,也同样会报跨域问题。
什么是预检请求?:当发生跨域条件时候
,览器先询问服务器,服务器租用当前网页所在的域名是否在服务器的许可名单之中 ,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求 ,否则就报错
。如下图
图片
开始动手模拟
:
Nginx代理端口:22222,配置如下
复制server { listen 22222; server_name localhost; location / { proxy_pass http://localhost:59200; } }1.2.3.4.5.6.7. 测试代理是否成功
,通过Nginx代理端口2222再次访问接口
,可以看到如下图通过代理后接口也是能正常访问
图片
接下来开始用网站8080访问Nginx代理后的接口地址,亿华云报错情况如下↓↓↓
情况1:
复制Access to XMLHttpRequest at http://localhost:22222/api/Login/TestGet from origin http://localhost:8080 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the requested resource.1.
图片
通过错误信息可以很清晰的定位到错误(注意看标红部分)priflight说明是个预请求 ,CORS 机制跨域会首先进行 preflight(一个 OPTIONS 请求)
, 该请求成功后才会发送真正的请求。这一设计旨在确保服务器对 CORS 标准知情,以保护不支持 CORS 的旧服务器
通过错误信息 ,我们可以得到是预检请求的请求响应头缺少了 Access-Control-Allow-Origin
,错哪里,我们改哪里就好了。修改Nginx配置信息如下(红色部分为添加部分),缺什么就补什么,模板下载很简单明了
复制server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin http://localhost:8080; proxy_pass http://localhost:59200; } }1.2.3.4.5.6.7.8. 哈哈 ,当满怀欢喜的以为能解决后
,发现还是报了同样的问题
图片
不过我们的配置没什么问题
,问题在Nginx
图片
add_header 指令用于添加返回头字段 ,当且仅当状态码为图中列出的那些时有效 。如果想要每次响应信息都携带头字段信息,需要在最后添加always(经我测试,只有Access-Control-Allow-Origin这个头信息需要加always,其他的不加always也会携带回来),那我们加上试试
复制server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin http://localhost:8080 always; proxy_pass http://localhost:59200; } }1.2.3.4.5.6.7.8. 修改了配置后,建站模板发现生效了 ,当然不是跨域就解决了,是上面这个问题已经解决了,因为报错内容已经变了
情况2 :
复制Access to XMLHttpRequest at http://localhost:22222/api/Login/TestGet from origin http://localhost:8080 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: It does not have HTTP ok status.1.
图片
通过报错信息提示可以得知,是跨域浏览器默认行为的预请求(option请求)没有收到ok状态码,此时再修改配置文件,当请求为option请求时候 ,给浏览器返回一个状态码(一般是204)
复制server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin http://localhost:8080 always; if ($request_method = OPTIONS) { return 204; } proxy_pass http://localhost:59200; } }1.2.3.4.5.6.7.8.9.10.11. 当配置完后,发现报错信息变了
情况3 :
复制Access to XMLHttpRequest at http://localhost:22222/api/Login/TestGet from origin http://localhost:8080 has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.1.
图片
意思就是预请求响应头Access-Control-Allow-Headers中缺少头信息authorization(各种情况会不一样 ,在发生跨域后,在自定义添加的头信息是不允许的,需要添加到请求响应头Access-Control-Allow-Headers中,以便浏览器知道此头信息的携带是服务器承认合法的
,我这里携带的是authorization
,其他的可能是token之类的,缺什么加什么)
,知道了问题所在,然后修改配置文件 ,添加对应缺少的部分,再试试
复制server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin http://localhost:8080 always; if ($request_method = OPTIONS) { add_header Access-Control-Allow-Headers authorization; #为什么写在if里面而不是接着Access-Control-Allow-Origin往下写?因为这里只有预检请求才会检查 return 204; } proxy_pass http://localhost:59200; } }1.2.3.4.5.6.7. 此时发现报错问题又回到了情况1
图片
经测试验证 ,只要if ($request_method = OPTIONS) 里面写了 add_header ,当为预检请求时外部配置的都会失效,为什么?↓↓
。
官方文档是这样说的:
There could be several add_header directives. These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level.
意思就是当前层级无 add_header 指令时,则继承上一层级的add_header
。相反的若当前层级有了add_header,就应该无法继承上一层的add_header
。
图片
配置修改如下:
复制server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin http://localhost:8080 always; if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin http://localhost:8080; add_header Access-Control-Allow-Headers authorization; return 204; } proxy_pass http://localhost:59200; } }1.2.3.4.5.6.7.8.9.10.11.12.13. 此时改完发现跨域问题已经解决了,
图片
不过以上虽然解决了跨域问题,但是考虑后期可能Nginx版本更新,不知道这个规则会不会被修改 ,考虑到这样的写法可能会携带上两个 Access-Control-Allow-Origin