CORS & nginx配置CORS实现跨域

出于安全原因,浏览器限制从脚本发起的跨源HTTP请求。例如,XMLHttpRequest和Fetch API遵循同源策略。这意味着,使用这些api的web应用程序只能从加载该应用程序的同一源请求资源,除非来自其他源的响应包含正确的CORS头文件。

image

同源和非同源请求 图片来源 https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

1 什么是同源策略(Same-origin policy)

简单来说就是一句话: URL中的协议名(scheme)、域名(host)、端口号(port)全部都得相等

 hierarchical part ┌───────────────────┴─────────────────────┐ authority path ┌───────────────┴───────────────┐┌───┴────┐ abc://username:[email protected]:123/path/data?key=value&key2=value2#fragid1 └┬┘ └───────┬───────┘ └────┬────┘ └┬┘ └─────────┬─────────┘ └──┬──┘ scheme user information host port query fragment

URL

URL 说明 是否允许通信 http://www.domain.com/a.js http://www.domain.com/b.js 同一域名,不同文件或路径 允许 http://www.domain.com/lab/c.js http://www.domain.com:8000/a.js http://www.domain.com/b.js 同一域名,不同端口 不允许 http://www.domain.com/a.js https://www.domain.com/b.js 同一域名,不同协议 不允许 http://www.domain.com/a.js http://192.168.4.12/b.js 域名和域名对应相同ip 不允许 http://www.domain.com/a.js http://x.domain.com/b.js 主域相同,子域不同 不允许 http://domain.com/c.js http://www.domain1.com/a.js http://www.domain2.com/b.js 不同域名 不允许

常见跨域场景

2 常见跨域解决方案

1、 通过jsonp跨域

2、 document.domain + iframe跨域

3、 location.hash + iframe

4、 window.name + iframe跨域

5、 postMessage跨域

6、 跨域资源共享(CORS)

7、 nginx代理跨域

8、 nodejs中间件代理跨域

9、 WebSocket协议跨域

3 什么是CORS(Cross-Origin Resource Sharing (CORS))

3.1 什么是CORS

MDN Cross-Origin Resource Sharing (CORS)

阮一峰 跨域资源共享 CORS 详解 关于CORS阮一峰老师写的绝对是经典

3.2 CORS分类

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

3.3 简单请求

1 Simple method: GET, POST or HEAD

2 Simple headers– the only allowed custom headers are:

  • Accept,
  • Accept-Language,
  • Content-Language,
  • Content-Type with the value application/x-www-form-urlencoded, multipart/form-data or text/plain.

3.4 非简单请求

除了简单请求都是非简单请求

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询(OPTIONS)请求,称为"预检"请求(preflight)有的场景忽略了预检请求的nginx配置,导致跨域配置失败

image

非简单请求 预检请求流程(OPTIONS)

4 nginx配置CORS

  • Access-Control-Allow-Origin 如果需要跨域发送cookie,不能配置* (这样会很不安全),需要配置具体的域名或者使用变量 $http_origin'(不安全)
  • Access-Control-Allow-Headers 根据实际情况增删
  • location 模块 / 代表通配符,所有请求都会走这里
  • always 参数 If the always parameter is specified (1.7.5), the header field will be added regardless of the response code. 无论响应代码如何,头字段都将被添加。

# # Wide-open CORS config for nginx # location / { if (request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; # # Custom headers and headers various browsers *should* be OK with but aren't # add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; always # # Tell client that this pre-flight info is valid for 20 days # add_header 'Access-Control-Max-Age' 1728000 always; add_header 'Content-Type' 'text/plain; charset=utf-8' always; add_header 'Content-Length' 0 always; return 204; } if (request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '' always; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always; } } 

https://enable-cors.org/server_nginx.html

踩坑

nginx: [emerg] "add_header" directive is not allowed here -

没有返回跨域头信息 - 可能只是配置了某个location下面的跨域头配置,可能是返回的状态码有404等状态码,浏览器不认可返回的跨域头配置

预检请求没通过 - 没有处理OPTIONS请求或者,OPTIONS没有返回对应的状态码

参考资料

阮一峰 跨域资源共享 CORS 详解

MDN Cross-Origin Resource Sharing (CORS)CORS on Nginx

Same-origin policy

前端常见跨域解决方案(全)

ngx_http_headers_module

你可能感兴趣的:(CORS & nginx配置CORS实现跨域)