首页 > 作文

Nginx 代理解决跨域问题多种情况分析

更新时间:2023-04-06 00:17:22 阅读: 评论:0

何为跨域问题

跨域本人经过两天的磨练,大量地翻阅网上资料,通俗地讲,就是,同一ip,同一域名,不同端口下,需要互相访问,需要cookie的传递以及数据的获取。

一般在项目中,前后端完全分离,因此访问的端口号不同,比如:localhost:8090(前端)发送到localhost:8001(后端)请求数据,此时前后端就出现了跨域问题。下面紧接着给大家介绍nginx 代理解决跨域问题分析,内容如下所示:

当你遇到跨域问题,不要立刻就选择复制去尝试。请详细看完这篇文章再处理 。我相信它能帮到你。

分析前准备:

前端网站地址:http://localhost:8080

服务端网址:http://localhost:59200

首先保证服务端是没有处理跨域的,其次,先用postman测试服务端接口是正常的

当网站8080去访问服务端接口时,就产生了跨域问题,那么如何解决?接下来我把跨域遇到的各种情况都列举出来并通过nginx代理的方式解决(后台也是一样的,只要你理解的原理)。

跨域主要涉及4个响应头:

access-control-allow-origin 用于设置允许跨域请求源地址 (预检请求和正式请求在跨域时候都会验证)

access-co对老师感谢的话ntrol-allow-headers跨域允许携带的特殊头信息字段(只在预检请求验证)

access-control-allow-methods跨域允许的请求方法或者说http动词(只在预检请求验证)

access-control-allow-credentials 是否允许跨域使用cookies,如果要跨域使用cookies,可以添加上此请求响应头,值设为true(设置或者不设置,都不会影响请求发送,只会影响在跨域时候是否要携带cookies,但是如果设置,预检请求和正式请求都需要设置)。不过不建议跨域使用(项目中用到过,不过不稳定,有些浏览器带不过去),除非必要,因为有很多方案可以代替。

网上很多文章都是告诉你直接nginx添加这几个响应头信息就能解决跨域,当然大部分情况是能解决,但是我相信还是有很多情况,明明配置上了,也同样会报跨域问题。

什么是预检请求?:当发生跨域条件时候,览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些http动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的xmlhttprequest请求,否则就报错。如下图

开始动手模拟:

nginx代理端口:22222 ,配置如下

rver {        listen       22222;        rver_name  localhost;        location  / {            proxy_pass  http://localhost:59200;        }}

测试代理是否成功,通过nginx代理端口2222再次访问接口,可以看到如下图通过代理后接口也是能正常访问

接下来开始用网站8080访问nginx代理后的接口地址,报错情况如下↓↓↓

情况1:

access to xmlhttprequest at ‘http://localhost:22222/api/login/testget’ from or节约时间的名言igin ‘http://localhost:8080’ has been blocked by cors policy: respon to preflight request doesn’t pass access control check: no ‘access-control-allow-origin’ header is prent on the requested resource.

通过错误信息可以很清晰的定位到错误(注意看标红部分)priflight说明是个预请求,cors 机制跨域会首先进行 preflight(一个 options 请求), 该请求成功后才会发送真正的请求。 这一设计旨在确保服务器对 cors 标准知情,以保护不支持 cors 的旧服务器

通过错误信息,我们可以得到是预检请求的请求响应头缺少了access-control-allow-origin,错哪里,我们改哪里就好了。修改nginx配置信息如下(红色部分为添加部分),缺什么就补什么,很简单明了

rver {        listen       22222;        rver_name  localhost;        location  / {           add_header access-control-allow-origin 'http://localhost:8080';           proxy_pass  http://localhost:59200;         }    }

哈哈,当满怀欢喜的以为能解决后,发现还是报了同样的问题

不过我们的配置没什么问题,问题在nginx,下图链接http://nginx.org/en/docs/http/ngx_http_headers_module.html

add_header 指令用于添加返回头字段,当且仅当状态码为图中列出的那些时有效。如果想要每次响应信息都携带头字段信息,需要在最后添加always(经我测试,只有access-control-allow-origin这个头信息需要加always,其他的不加always也会携带回来),那我们加上试试

rver {        listen       22222;        rver_name  localhost;        location  / {           add_header access-control-allow-origin 'http://localhost:8080' always;           proxy_pass  http://localhost:59200;         }    }

修改了配置后,发现生效了,当然不是跨域就解决了,是上面这个问题已经解决了,因为报错内容已经变了

情况2:

access to xmlhttprequest at ‘http://localhost:22222/api/login/testget’ from origin ‘http://localhost:8080’ has been火爱 blocked by cors policy: respon to preflight request doesn’t pass access control check: it does not have http ok status.

通过报错信息提示可以得知,是跨域浏览器默认行为的预请求(option请求)没有收到ok状态码,此时再修改配置文件,当请求为option请求时候,给浏览器返回一个状态码(一般是204)

rver {        listen       22222;        rver_name  localhost;        location  / {           add_header access-control-allow-origin 'http://localhost:8080' always;           if ($request_method = 'options') {                return 204;           }           proxy_pass  http://localhost:59200;         }    }

当配置完后,发现报错信息变了

情况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 respon.

意思就是预请求响应头access-control-allow-headers中缺少头信息authorization(各种情况会不一样,在发生跨域后,在自定义添加的头信息是不允许的,需要添加到请求响应头access-control-allow-headers中,以便浏览器知道此头信息的携带是服务器承认合法的,我这里携带的是authorization,其他的可能是token之类的,缺什么加什么),知道了问题所在,然后修改配置文件,添加对应缺少的部分,再试试

rver {        listen       22222;        rver_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

经测试验证,只要if ($request_method = ‘options’) 里面写了add_header ,当为预检请求时外部配置的都会失效,为什么? ↓↓。

官方文档是这样说的:

there could be veral add_header directives. the 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。

配置修改如下:

rver {        listen       22222;        rver_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;         }    }

此时改完发现跨域问题已经解决了,

不过以上虽然解决了跨域问题,但是考虑后期可能nginx版本更新,不知道这个规则会不会被修改,考虑到这样的写法可能会携带上两个access-control-allow-origin ,这种情况也是不允许的,下面会说到。所以配置适当修改如下:

rver {        listen       22222;        rver_name  localhost;        location  / {            if ($request_method = 'options') {                add_header access-control-allow-origin 'http://localhost:8080';                add_header access-control-allow-headers 'authorization';                return 204;            }            if ($request_method != 'options') {                add_header access-control-allow-origin 'http://localhost:8080' always;            }            proxy_pass  http://localhost:59200;         }    }

还没完,继续聊 ↓↓

情况4:

比较早期的api可能只用到了post和get请求,而access-control-allow-methods这个请求响应头跨域默认只支持post和get,当出现其他请求类型时候,同样会出现跨域异常。

比如,我这里将请求的api接口请求方式从原来的get改成put,在发起一次试试。在控制台上会抛出错误:

access to xmlhttprequest at ‘http://localhost:22222/api/login/testget’ from origin ‘http://localhost:8080’ has been blocked by cors policy: method put is not allowed by access-control-allow-methods in preflight respon.

报错内容也讲的很清楚,在这个预请求中,put方法是不允许在跨域中使用的,我们需要改下access-control-allow-methods的配置(缺什么加上么,这里我只加了put,可以自己加全一点),让浏览器知道服务端是允许的

rver {    listen 22222;    rver_name localhost;    location / {        if ($request_method = 'options') {            add_header access-control-allow-origin 'http://localhost:8080';            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 'http://localhost:8080' always;        }        proxy_pass http://localhost:59200;    }}

这里注意一下,改成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 ‘http://localhost:22222/api/login/testget’ from origin ‘http://localhost:8080’ has been blocked by cors policy: the ‘access-control-allow-origin’ header contains multiple values ‘*, http://localhost:8080’, but only one is allowed.

意思就是此刻access-control-allow-origin请求响应头返回了多个,而只允许有一个,这种情况当然修改配置去掉access-control-allow-origin这个配置就可以了,不过遇到这种情况,建议nginx配置和服务端自己解决跨域只选其一。(这里注意如果按我上面的写法,if $request_method = ‘options’ 这个里面的access-control-allow-origin可不能删除,删除!=’options’里面的就好了,因为这里如果是预检请求直接就ruturn了,请求不会再转发到59200服务,如果也删除了,就会报和情况1一样的错误。所以为什么说要不服务端代码层面解决跨域,要不就nginx代理解决,不要混着搞,不然不明白原理的人,网上找一段代码贴就很可能解决不了问题)

↓↓↓↓↓

再贴一份完整配置(*号根据自己‘喜好’填写):

rver {        listen       22222;        rver_name  localhost;        location  / {            if ($request_method = 'options') {                add_header access-control-allow-origi古筝谱子n 'http://localhost:8080';                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 'http://localhost:8080' always;                add_header access-control-allow-credentials 'true';            }            proxy_pass  http://localhost:59200;         }    }

或者:

rver {        listen       22222;        rver_name  localhost;        location  / {            add_header access-control-allow-origin 'http://localhost:8080' 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  http://localhost:59200;         }    }

最后,这是一篇解决跨域遇到问题解决问题的过程,如果认真看完了,我相信应该都能很容易的理解,并且在实际使用中自己解决该问题,希望能帮助到大家,以上内容都是自己理解自己测试码出来的,如有理解不对的地方,望大家指正。

到此这篇关于nginx 代理解决跨域问题分析的文章就介绍到这了,更多相关nginx 代理解决跨域内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

本文发布于:2023-04-06 00:17:11,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/5d739b4c5e1b890359cd670dd0c16b7c.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:Nginx 代理解决跨域问题多种情况分析.doc

本文 PDF 下载地址:Nginx 代理解决跨域问题多种情况分析.pdf

标签:情况   服务端   信息   报错
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图