从此再也不担心Nginx跨域设置了
Posted 木讷大叔爱运维
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从此再也不担心Nginx跨域设置了相关的知识,希望对你有一定的参考价值。
CORS是项目中经常遇到的问题,需要花费较多的时间去解决。而nginx是项目中使用非常多的反向代理,下面我们来介绍下从Nginx上处理CORS跨域问题,彻底处理掉CORS这个纸老虎。
CORS
CORS是一个W3C标准,全称是跨域资源共享(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
简单来说就是跨域的目标服务器要返回一系列的Headers,通过这些Headers来控制是否同意跨域。
CORS提供的Headers,在Request包和Response包中都有一部分:
#HTTP Response Header
Access-Control-Allow-Origin
Access-Control-Allow-Credentials
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Expose-Headers
Access-Control-Max-Age
#HTTP Request Header
Access-Control-Request-Method
Access-Control-Request-Headers
其中Access-Control-Allow-Headers一般包含基本字段,如Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma;对于其他字段,就必须在Access-Control-Expose-Headers里面指定。
CORS分类
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
1.简单请求
只要同时满足以下两大条件,就属于简单请求凡是不同时满足上面两个条件,就属于非简单请求。
#1.请求方法是以下三种方法之一:
HEAD
GET
POST
#2.HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
2.非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT、DELETE或OPTIONS,或者Content-Type字段的类型是application/json。
项目中后端一般使用json格式返回前端请求的数据,因此非简单请求的跨域比较容易出现。
跨域处理方式
为什么要讲简单请求和非简单请求呢?因为浏览器对这两种请求的处理,请求过程是不一样的。
1.简单请求
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中增加一个Origin字段。处理如下:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
在Nginx上使用如上配置,一般能够解决简单请求的跨域处理。
CORS请求默认不发送Cookie和HTTP认证信息。但是如果要把Cookie发到服务器,要服务器同意,指定Access-Control-Allow-Credentials字段。
add_header 'Access-Control-Allow-Credentials' 'true';
需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。
2.非简单请求
非简单CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight),预捡的请求方法是OPTIONS。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。
因此我们可以在浏览器的开发者工具中查看头信息,若头信息中有OPTIONS方法,说明此次CORS请求是非简单请求,需要nginx中添加以下头信息:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
此时虽然我们已经添加了所有的Methods方法,但是预检请求仍不会通过,此时nginx对OPTIONS方法返回"405 Method Not Allowed”或者403。因为Nginx默认不会对OPTIONS方法返回200,需要在nginx对OPTIONS方法进行额外处理,如下:
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
return 200;
}
或
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'Content-Type';
#在location处添加以下内容
if ($request_method = 'OPTIONS') {
return 200;
}
Nginx经过以上设置通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。
总结
以前完全忽略了CORS的简单请求和非简单请求,以为配置了Origins和Method就可以了,但是问题依然得不到解决。通过本文介绍,也算是对处理CORS问题进行了总结,希望在以后的项目中我们能够快速解决。但在nginx配置CORS跨域并不能彻底就解决跨域问题,而且如果后端java也配置了跨域策略,还可能出现二次跨域问题。因此最好的方式是跨域统一在后端处理。
以上是关于从此再也不担心Nginx跨域设置了的主要内容,如果未能解决你的问题,请参考以下文章
一键搞定cookie跨域问题,麻麻再也不用担心我拿不到cookie了