使用nginx代理解决跨域问题

请分析下,使用nginx代理解决跨域问题
最新回答
关于鹿的诗

2024-09-20 01:54:02

   先说说跨域这事情吧。早在13年,我刚接触
前端开发
的时候就遇到了跨域,那时候刚开始流行前后端分离。解决跨域就是直接用get jsonp。还是小白的我,也没有去想跨域的其它解决方式和为什么要采用这种解决方式。

   最近,做一个二次开发的项目,也碰到了用网页请求http post,浏览器跨域,不能获取返回数据的问题,所以再次来梳理下这个跨域,为什么最后选择了nginx代理。

  首先,什么是跨域呢?首先需要了解的是同源和跨源的概念。对于相同源,其定义为:如果协议、端口(如果指定了一个)和主机对于两个页面是相同的,则两个页面具有相同的源。 只要三者之一任意一点有不同,那么就为不同源。
同源策略
限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。当一个资源从与该资源本身所在的服务器的域或端口不同的域或不同的端口请求一个资源时,资源会发起一个跨域 HTTP 请求。跨域不一定是浏览器限制了发起跨站请求,而也可能是跨站请求可以正常发起,但是返回结果被浏览器拦截了。 简单的来说,出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,即“同源策略”。而跨域就是通过某些手段来绕过同源策略限制,实现不同服务器之间通信的效果。

  跨域的解决方案也有很多种。

  类型一:有些浏览器可以设置 ,降低它的安全性。但是对于一个网站,要求设置浏览器是不切合实际的。

  类型二:直接用form方式 ,这种情况下不是ajax请求,而是直接访问目标地址了,不存在跨域问题,但是这个页面已经跳转了。而我们想实现的只是取另外一个地址的数据到本地显示而已。

  类型三:服务端语言是能够处理的情况下。

     1、CORS 是一个
W3C标准
,全称是”跨域资源共享”(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。跨域资源共享( CORS )机制允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。其需要服务端和客户端同时支持。

   对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror
回调函数
捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。 Access-Control-Allow-Origin 该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。 Access-Control-Allow-Credentials 该字段可选。 Access-Control-Expose-Headers 该字段可选。

   可以说这种办法主要在header上下功夫,设置Access-Control-Allow-Origin为所有*允许访问。虽然说它支持所有的请求方式,post,delete,put等等,但是它不能兼容ie6,7等等。

   例如下图的nodejs  express 例子:

   2、服务端的http ajax请求全部改为 get jsonp方式 。该方式能够兼容老式浏览器。

    3、iframe window.name 这种传值得方式很巧妙,兼容性也很好。但是在要访问数据的地址那个服务器要有一个空的中间页面拿来用。

    4、postMessage , html5 window.postMessage。 同iframe window.name有点像,也是需要服务端有个空的html拿来接收数据。而且现在的postMessage兼容性也不好。

  5、document.domain 修改为
顶级域名


  6、 WebSocket ,协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

类型四:不是简单的前后端。假如有个第三方的api,自己有一个网站前端,一个网站后端。

  1、自己的网站端和后端源码放在同一个服务端口和目录下,不存在跨域。当直接用网站前端的http访问第三方api,浏览器跨域。此时,改为由网站后端的服务端语言访问,做个中间人,将访问的数据给网页前端。

  2、网站前端和后端不是同源的,采用以上的跨域方案,譬如CORS。同样的网站后端做中间人,访问第三方api,再转给网页前端。

  3、使用nginx
反向代理
解决跨域问题。 网站前端访问nginx服务的地址,nginx设置代理地址为访问第三方api地址,当访问代理地址的时候,浏览器访问的是nginx服务的地址,实际是访问第三方api地址。

    注意:此时,如果目录下有个proxy.html,因为设置代理地址是/proxy,碰到这个地址就被转到”
https://192.168.18.175:8088/api/v1.0.2/
“,所以要访问proxy.html是访问不到的。

   4、使用nginx代理地址是解决生产环境发布的问题了,那么我在开发的时候使用angular这样需要打包的框架怎么办呢。当然在开发环境下,angular也是由类似代理地址的解决方案的。

(1)创建配置代理文件:假设后端服务的访问地址为
http://192.168.19.175:8088/api/v1.0.2/login
,我们可以创建一个proxy.conf.json文件,放在package.json同目录下。

(2)改写package.json文件 ,采用--proxy-config命令(angular自带的命令)。

(3)ajax访问代理地址

    此时, 执行 npm start ,即可发现,浏览器访问
http://localhost:4200/api/v1.0.2/login
的同源地址,实际上是访问
http://192.168.18.175:8088/api/v1.0.2/login.


   angular在开发环境下代理地址的方法类似在生产环境下使用的nginx代理。但是测试angular是有一个/api代理地址的巧合。刚好第三方api上面的地址有个api,才能使用这个地址,并且能够简写一个api,才能成功访问,如果更改为其它的,譬如proxy,就测试失败。而且proxy.conf.json文件下的设置也只能是域名和端口。所以,本人测试,这或许是个巧合或者是缺陷。

五、其它

  当然,跨域这个算是历史性的问题,以后也会存在这个问题。除了上面各种方法,以及根据各种方法使用的场合,还有许多其它的方法。例如各大流行框架react,vie应该也有像angular一样,能够处理跨域的开发环境方案,接下来,还是要继续学习和积累。