Nginx 解决跨域问题

Nginx 解决跨域问题

  • 问题由来
  • Jsonp 的解决之道
  • CORS 的解决之道
  • nginx 配置跨域操作(CORS)
    • 简单请求
    • 复杂请求
  • CORS 对比反向代理

问题由来

浏览器拒绝执行其它域名下的 ajax 运作:

我想自己做一个搜索网站,但我不会搜索技术,怎么办呢?如果能发起 ajax 请求到百度就好了呢,可以这样吗?
肯定不行,如果浏览器在自己的服务器域名对应的 html 页面内,发起 ajax 请求偷盗 www.baidu.com 域名下的内容来填充自己的页面,整个互联网秩序将混乱。

为了防止这种混乱,W3C 组织制定了浏览器安全规范,即 html 页面发起的 ajax 请求仅限于同域名后端范围,跨越域名的ajax请求不得执行,此谓跨域问题。
如下图:
Nginx 解决跨域问题_第1张图片
Nginx 解决跨域问题_第2张图片
而在日常工作中,我们自己有多个子系统,避免不了要有跨越子系统的 ajax 请求,此时,我们希望自己内部的各个子系统不必有这种跨域限制

Jsonp 的解决之道

W3C 制定的规则不允许ajax跨域请求,却允许script标签发起跨域请求,如下:
Nginx 解决跨域问题_第3张图片
因此,有人便扩展的 script 标签 src 源可以跨域的用法,来得到跨域名的请求信息。这便是 jsonp 的解决办法。
jsonp 的方法有其不美的地方,主要是两点:

  1. jsonp只能解决 GET 类的请求,其它类型的请求,script 标签无法做到
  2. 使用 jsonp 的方式,对应的后台程序必须对结果进行改造。将返回值做一个函数式包装。这对业务开发有较大侵入性,增加开发人员负担

CORS 的解决之道

Cross-Origin Resource Sharing (CORS),跨域资源共享。

W3C 制定跨域限制的本意,是防止页面领域安全混乱,即防止A公司不经B公司同意,使用 ajax 盗取B公司的服务内容。
出于这个本意,W3C改进了跨域的方案,即:如果B公司是同意将自己的内容分享给A公司的,跨域限制可放开,此方案即CORS方案,如下图:

Nginx 解决跨域问题_第4张图片

nginx 配置跨域操作(CORS)

server {
        listen       80;
        server_name  test.enjoy.com;
        
	#是否允许请求带有验证信息
	add_header Access-Control-Allow-Credentials true;
	#允许跨域访问的域名,可以是一个域的列表,空格隔开,也可以是通配符*(不建议)
	add_header Access-Control-Allow-Origin  http://static.enjoy.com;
	#允许使用的请求方法,以逗号隔开,可以用 *
	add_header Access-Control-Allow-Methods 'POST,GET,OPTIONS,PUT,DELETE';
	#预检命令的缓存,如果不缓存每次会发送两次请求,单位为秒。
	#第一次是浏览器使用OPTIONS方法发起一个预检请求,第二次才是真正的异步请求
    add_header Access-Control-Max-Age 3600;
    
	#允许脚本访问的返回头
	add_header Access-Control-Allow-Headers 'x-requested-with,content-type,Cache-Control,Pragma,Date,x-timestamp';	
	#允许自定义的头部,以逗号隔开,大小写不敏感
	add_header Access-Control-Expose-Headers 'WWW-Authenticate,Server-Authorization';
	#P3P支持跨域cookie操作
	add_header P3P 'policyref="/w3c/p3p.xml", CP="NOI DSP PSAa OUR BUS IND ONL UNI COM NAV INT LOC"';
	
	if ($request_method = 'OPTIONS') {##OPTIONS类的请求,是跨域先验请求
            return 204;##http状态码 204 (无内容) 服务器成功处理了请求,但没有返回任何内容。可以返回 200 
        }
}

简单请求

对于比较简单的http请求(GET、POST、HEAD类型),无须浏览器来问,nginx服务器直接在响应头部,加入同意跨域的信号即可
Nginx 解决跨域问题_第5张图片

复杂请求

对于复杂的http请求(PUT、DELETE、含json格式数据),浏览器会在发请求前,先发一道 OPTION 请求来询问。我们在Nginx上直接配置对此询问的回答即可
在这里插入图片描述
有了上述Nginx的两道配置,跨域问题自然而解,对业务毫无侵入性。Nginx 解决跨域问题_第6张图片

CORS 对比反向代理

什么是反向代理:代理与反向代理
如何配置:proxy_pass 代理转发

对比两者,可以看到,两者适合的业务场景有不同:

反向代理

  • 将一台服务器作为网关和代理服务器,负责将请求转发到子系统(其它服务器)。
  • 用户的角度看,我只访问了一个域名,但其实可能你访问了很多服务器。
  • 是在访问其它服务器的服务器上配置(要转发到的服务器)。

跨域资源共享

  • 从 ajax 里拿其它服务器的资源。
  • 可以看到,这个主要是为了解决前端人员的问题。但 ajax 里其实就有一个 url 参数,所以反向代理也能解决这个问题。
  • 是在被访问的服务器上配置(允许访问其的服务器)。

所以综合二者业务场景的不同,我认为:

  1. 首先,确实进行了业务拆分,有业务在其他的服务器上,先配置 location,使用反向代理,这是必须的。做了这一步,你就已经解决了一部分跨域问题。
  2. 上面一步做完了以后,优先运用 CORS,毕竟这才是专业的跨域解决方案,并且是官方的。而且它配置比较简单,基本上配置一个允许访问的域名就行了,其它的都是不怎么变的。

你可能感兴趣的:(Nginx基础与进阶)