CORS跨域

IT知识
499
0
0
2022-11-16
标签   跨域请求

01、索引

waterflow.link/articles/1665656761...

1、为什么跨域

跨域资源共享 (CORS) 是一种基于 HTTP 标头的机制,它允许服务器指示除其自身之外的任何来源(域、方案或端口),浏览器应允许从中加载资源。 CORS 还依赖于一种机制,浏览器通过该机制向托管跨域资源的服务器发出“预检”请求,以检查服务器是否允许实际请求。 在该预检中,浏览器发送指示 HTTP 方法的标头和将在实际请求中使用的标头。

跨域请求的示例:从 a.com 提供的前端 JavaScript 代码使用 ajax 向 b.com/data.json 发出请求。

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

2、跨域的规则

CORS标准通过添加新的 HTTP 头来工作,服务器可以返回允许哪些来源从 Web 浏览器读取该信息。此外,对于可能对服务器数据造成副作用的 HTTP 方法(特别是 GET 以外的 HTTP方法 ,或具有某些 MIME 类型的 POST),规范要求浏览器“预检”请求(先发送OPTIONS请求),然后在服务器“允许”后发送实际请求。

CORS 失败会导致错误,但出于安全原因,JavaScript 无法获得有关错误的详细信息。所有代码都知道发生了错误。确定具体出了什么问题的唯一方法是查看浏览器的控制台以获取详细信息。

3、跨域场景

1、不会触发预检

简单的请求不会触发预检,那什么是简单的请求呢?

  • 首先请求方法必须是GET、HEAD、POST其中之一
  • 除了客户端自动设置的header头(比如:Connection、User-Agent等),只能设置如下的这些header头
  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type:只允许application/x-www-form-urlencoded、multipart/form-data、text/plain类型
  • Range:只能是一些简单的header头,比如bytes=256-或者bytes=127-255

下面是一个简单请求的流程:

https://www.leyeah.com/upload/cms-images/2022/11/16/6374bbbd98ecc.jpg

  1. 首先客户端会向a.com会向服务端b.com发送请求,并带上源域名。
  2. 作为响应,服务器返回一个带有 Access-Control-Allow-Origin: * 的 Access-Control-Allow-Origin 标头,这意味着该资源可以被任何来源访问。(一般允许某个域或者某几个域,可以用正则)

2、会触发预检

和简单请求不同,处于安全考虑,会先向“预检”请求,浏览器首先使用 OPTIONS 方法向另一个源上的资源发送 HTTP 请求,以确定实际请求是否可以安全发送。

下面是预检请求的流程:

https://www.leyeah.com/upload/cms-images/2022/11/16/6374bbbdd73b8.jpg

  1. 首先客户端header头已经不符合简单请求的header,这时会触发预检。
  2. 客户端发送OPTIONS请求,以获取允许跨域的header头,会返回204 No Content的状态码
  3. 预检成功之后,客户端会发送正常的POST请求

3、nginx跨域配置

注意:如果nginx设置跨域重复,客户端console也会提示重复跨域

add_header Access-Control-Allow-Origin * always; # 允许所有
add_header Access-Control-Allow-Methods 'PUT,POST,GET,DELETE,OPTIONS'; #允许指定的请求方法
add_header Access-Control-Allow-Headers 'token,eceibstoken,powercode,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; # 允许指定的header头
add_header Access-Control-Expose-Headers *; # 指定客户端可以访问哪些header
# 如果是预检请求,返回204
if ($request_method = OPTIONS) {
    return 204;
}