探索小游戏大厅的多样性与未来发展趋势
2008
2022-08-28
解决 用 Nginx 处理 跨域问题
教你 如何 快速 用 Nginx 轻松搞定跨域问题
当你遇到跨域问题,不要立刻就选择复制去尝试。请详细看完这篇文章再处理 。我相信它能帮到你。
分析前准备:
前端网站地址:(预检请求和正式请求在跨域时候都会验证)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 }}
测试代理是否成功,通过Nginx代理端口2222再次访问接口,可以看到如下图通过代理后接口也是能正常访问
接下来开始用网站8080访问Nginx代理后的接口地址,报错情况如下↓↓↓
情况1:
“Access to XMLHttpRequest at ‘from origin ‘has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin ' proxy_pass } }
哈哈,当满怀欢喜的以为能解决后,发现还是报了同样的问题
不过我们的配置没什么问题,问题在Nginx,下图链接指令用于添加返回头字段,当且仅当状态码为图中列出的那些时有效。如果想要每次响应信息都携带头字段信息,需要在最后添加always(经我测试,只有Access-Control-Allow-Origin这个头信息需要加always,其他的不加always也会携带回来),那我们加上试试
server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin 'always; proxy_pass } }
修改了配置后,发现生效了,当然不是跨域就解决了,是上面这个问题已经解决了,因为报错内容已经变了
情况2:
“Access to XMLHttpRequest at ‘from origin ‘has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: It does not have HTTP ok status.
server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin 'always; if ($request_method = 'OPTIONS') { return 204; } proxy_pass } }
当配置完后,发现报错信息变了
情况3:
“Access to XMLHttpRequest at ‘from origin ‘has been blocked by CORS policy: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response.
server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin 'always; if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Headers 'authorization'; #为什么写在if里面而不是接着Access-Control-Allow-Origin往下写?因为这里只有预检请求才会检查 return 204; } proxy_pass }}
此时发现报错问题又回到了情况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 'always; if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin ' add_header Access-Control-Allow-Headers 'authorization'; return 204; } proxy_pass } }
此时改完发现跨域问题已经解决了,
不过以上虽然解决了跨域问题,但是考虑后期可能Nginx版本更新,不知道这个规则会不会被修改,考虑到这样的写法可能会携带上两个 Access-Control-Allow-Origin ,这种情况也是不允许的,下面会说到。所以配置适当修改如下:
server { listen 22222; server_name localhost; location / { if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin ' add_header Access-Control-Allow-Headers 'authorization'; return 204; } if ($request_method != 'OPTIONS') { add_header Access-Control-Allow-Origin 'always; } proxy_pass } }
还没完,继续聊 ↓↓
情况4:比较早期的API可能只用到了POST和GET请求,而Access-Control-Allow-Methods这个请求响应头跨域默认只支持POST和GET,当出现其他请求类型时候,同样会出现跨域异常。比如,我这里将请求的API接口请求方式从原来的GET改成PUT,在发起一次试试。在控制台上会抛出错误:
“Access to XMLHttpRequest at ‘from origin ‘has been blocked by CORS policy: Method PUT is not allowed by Access-Control-Allow-Methods in preflight response.
server { listen 22222; server_name localhost; location / { if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin ' add_header Access-Control-Allow-Headers 'content-type,authorization'; add_header Access-Control-Allow-Methods 'PUT';#为这么只加在这个if中,不再下面的if也加上?因为这里只有预检请求会校验,当然你加上也没事。 return 204; } if ($request_method != 'OPTIONS') { add_header Access-Control-Allow-Origin 'always; } proxy_pass }}
这里注意一下,改成PUT类型后,Access-Control-Allow-Headers请求响应头又会自动校验content-type这个请求头,和情况3是一样的,缺啥补啥就行了。如果不加上content-type,则会报如下错误。(想简单的话,Access-Control-Allow-Headers和Access-Control-Allow-Methods可以设置为 * ,表示全都匹配。但是Access-Control-Allow-Origin就不建议设置成 * 了,为了安全考虑,限制域名是很有必要的。
都加上后,问题就解决了,这里报405是我服务端这个接口只开放了GET,没有开放PUT,而此刻我将此接口用PUT方法去请求,所以接口会返回这个状态码。
情况5:最后再说一种情况,就是后端处理了跨域,就不需要自己在处理了(这里吐槽下,某些后端工程师自己改服务端代码解决跨域,但是又不理解其中原理,网上随便找段代码黏贴,导致响应信息可能处理不完全,如method没添加全,headers没加到点上,自己用的那个可能复制过来的并不包含实际项目所用到的,没有添加options请求返回状态码等,导致Nginx再用通用的配置就会可能报以下异常)
“Access to XMLHttpRequest at ‘from origin ‘has been blocked by CORS policy: The ‘Access-Control-Allow-Origin’ header contains multiple values ‘*, but only one is allowed.
再贴一份完整配置(*号根据自己‘喜好’填写):
server { listen 22222; server_name localhost; location / { if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin ' add_header Access-Control-Allow-Headers '*'; add_header Access-Control-Allow-Methods '*'; add_header Access-Control-Allow-Credentials 'true'; return 204; } if ($request_method != 'OPTIONS') { add_header Access-Control-Allow-Origin 'always; add_header Access-Control-Allow-Credentials 'true'; } proxy_pass } }
或者:
server { listen 22222; server_name localhost; location / { add_header Access-Control-Allow-Origin 'always; add_header Access-Control-Allow-Headers '*'; add_header Access-Control-Allow-Methods '*'; add_header Access-Control-Allow-Credentials 'true'; if ($request_method = 'OPTIONS') { return 204; } proxy_pass } }
最后,这是一篇解决跨域遇到问题解决问题的过程,如果认真看完了,我相信应该都能很容易的理解,并且在实际使用中自己解决该问题,希望能帮助到大家,以上内容都是自己理解自己测试码出来的,如有理解不对的地方,望大家指正。
总结
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看,您的支持是我坚持写作最大的动力。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~