首页
Javascript
Html
Css
Node.js
Electron
移动开发
小程序
工具类
服务端
浏览器相关
前端收藏
其他
关于
公司注册

nginx实现CORS跨域配置

2018年06月20日 转载自 man8er 阅读(7811)

简介

之前项目中遇到过几次跨域访问,通过百度或谷歌查询在nginx配置相关header予以解决,若不管用就没其他办法了;从来没有真正深入了解过,下面我们就来认识下CORS及在nginx中如何配置。

CORS

CORS是一个W3C标准,全称是跨域资源共享(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

简单来说就是跨域的目标服务器要返回一系列的Headers,通过这些Headers来控制是否同意跨域。
CORS提供的Headers,在Request包和Response包中都有一部分:

  1. #HTTP Response Header
  2. Access-Control-Allow-Origin
  3. Access-Control-Allow-Credentials
  4. Access-Control-Allow-Methods
  5. Access-Control-Allow-Headers
  6. Access-Control-Expose-Headers
  7. Access-Control-Max-Age
  8. #HTTP Request Header
  9. Access-Control-Request-Method
  10. 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. 1.请求方法是以下三种方法之一:
  2. HEAD
  3. GET
  4. POST
  5. 2.HTTP的头信息不超出以下几种字段:
  6. Accept
  7. Accept-Language
  8. Content-Language
  9. Last-Event-ID
  10. Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

凡是不同时满足上面两个条件,就属于非简单请求。
2.非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUT、DELETE或OPTIONS,或者Content-Type字段的类型是application/json。

跨域处理方式

为什么要讲简单请求和非简单请求呢?因为浏览器对对这两种请求的处理,是不一样的。
1.简单请求
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
处理如下:

  1. add_header 'Access-Control-Allow-Origin' '*';
  2. add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
  3. add_header 'Access-Control-Allow-Headers' 'Content-Type';

在nginx上经以上配置,一般能够解决简单请求的跨域处理。
CORS请求默认不发送Cookie和HTTP认证信息。但是如果要把Cookie发到服务器,要服务器同意,指定Access-Control-Allow-Credentials字段。

  1. add_header 'Access-Control-Allow-Credentials' 'true';

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。
2.非简单请求
(1)非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight), 预捡的请求方法是OPTIONS。浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。
因此我们可以在浏览器的开发者工具中查看头信息,若头信息中有OPTIONS方法,说明此次CORS请求是非简单请求,需要在nginx中添加头:

  1. add_header 'Access-Control-Allow-Origin' '*';
  2. add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
  3. add_header 'Access-Control-Allow-Headers' 'Content-Type';

此时虽然我们已经添加了所有的Methods方法,但是预检请求仍不会通过,因此此时nginx对OPTIONS方法返回”405 Method Not Allowed”或者403。我们需要在nginx对OPTIONS方法进行处理,如下:

  1. if ($request_method = 'OPTIONS') {
  2. add_header 'Access-Control-Allow-Origin' '*';
  3. add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
  4. add_header 'Access-Control-Allow-Headers' 'Content-Type';
  5. return 200;
  6. }
  7. add_header 'Access-Control-Allow-Origin' '*';
  8. add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
  9. add_header 'Access-Control-Allow-Headers' 'Content-Type';
  10. #在location处添加以下内容
  11. if ($request_method = 'OPTIONS') {
  12. return 200;
  13. }

我们在nginx上将OPTIONS方法返回200,而不是405或403。

(2)服务器经过以上设置通过了”预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。

总结

以前完全忽略了CORS的简单请求和非简单请求,以为陪着了Origins和Method就可以了。通过此次了解,其实之前文档有提到过,但是没有沉下心仔细研究。
在此特别引用一下两篇博文:
Nginx通过CORS实现跨域
跨域资源共享 CORS 详解

© 本文著作权归原作者所有 来源:man8er 阅读原文