Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浏览器同源策略/跨域方案 #21

Open
canvascat opened this issue Jun 28, 2021 · 2 comments
Open

浏览器同源策略/跨域方案 #21

canvascat opened this issue Jun 28, 2021 · 2 comments

Comments

@canvascat
Copy link
Owner

浏览器的同源策略(Same Origin Policy)

源(Origin)是由 URL 中 protocolhost(domain)以及 port 共同组成的部分。协议、主机名(域名)、端口号完全相同时,才是同源

http://localhost:3000/index.html#home
|协议  |  主机名  |端口|

访问非同源资源时就会产生跨源,即跨域。同源策略就是用来限制其中一些跨源访问的:

  • 无法获取非同源 iframedom
  • 无法获取非同源页面的 CookieStorage
  • 无法向非同源服务器发送 Ajax 请求。

https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

@canvascat
Copy link
Owner Author

跨域方案

跨域资源共享

跨域资源共享(CORS,Cross-Origin Resource Sharing)是浏览器为 AJAX 请求设置的一种跨域机制,让其可以在服务端允许的情况下进行跨域访问。主要通过 HTTP 响应头来告诉浏览器服务端是否允许当前域的脚本进行跨域访问。

跨域资源共享将 AJAX 请求分成了两类:简单请求和非简单请求。其中简单请求符合下面 2 个特征。

  • 请求方法为 GET、POST、HEAD
  • 请求头只能使用下面的字段:
    • Accept:浏览器能够接受的响应内容类型
    • Accept-Language:浏览器能够接受的自然语言列表
    • Content-Type:请求对应的类型,只限于 text/plainmultipart/form-dataapplication/x-www-form-urlencoded
    • Content-Language:浏览器希望采用的自然语言
    • Save-Data:浏览器是否希望减少数据传输量

任意一条要求不符合的即为非简单请求。

对于简单请求,处理流程如下:

  • 浏览器发出简单请求时会在请求头部增加一个 Origin 字段,对应的值为当前请求的源信息;
  • 当服务端收到请求后,会根据请求头字段 Origin 做出判断后返回相应的内容;
  • 浏览器收到响应报文后根据响应头 Access-Control-Allow-Origin 判断是否抛出错误,该字段值为服务端允许跨域请求的源,通配符“*”表示允许所有跨域请求。

所以对于简单请求,服务器只需要设置响应头中的 Access-Control-Allow-Origin 即可。


当处理非简单的请求时,浏览器会先发出一个预检请求(Preflight)。这个预检请求为 OPTIONS 方法,并会添加了 1 个请求头部字段 Access-Control-Request-Methods,值为跨域请求所使用的请求方法。

下图是一个POST请求以及预检请求的请求报文和响应报文。因为添加了不属于上述简单请求的头部字段'Content-Type': 'application/json;charset=UTF-8',所以浏览器在预检请求头部添加了 Access-Control-Allow-Headers: content-type

image

在服务端收到预检请求后,除了在响应头部添加 Access-Control-Allow-Origin 字段之外,至少还会添加 Access-Control-Allow-Methods 字段来告诉浏览器服务端允许的请求方法,并返回 204 状态码。

在上面的例子中,服务端还根据浏览器的 Access-Control-Request-Headers 字段回应了一个 Access-Control-Allow-Headers 字段,来告诉浏览器服务端允许的请求头部字段。

浏览器得到预检请求响应的头部字段之后,会判断当前请求服务端是否在服务端许可范围之内,如果在则继续发送跨域请求,反之则直接报错。比如上述例子服务器若未回应 Access-Control-Allow-Headers 字段,则会抛出错误 Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.

与跨域相关的协议头

Request Headers 说明
Origin 表明预检请求或实际请求的源站 URI
Access-Control-Request-Method 将实际请求所使用的 HTTP 方法告诉服务器
Access-Control-Request-Headers 将实际请求所携带的首部字段告诉服务器
Response Headers 说明
Access-Control-Allow-Origin 指定允许访问该资源的外域 URI,对于携带身份凭证的请求不可使用通配符*
Access-Control-Allow-Methods 指明实际请求所允许使用的 HTTP 方法
Access-Control-Allow-Headers 指明实际请求中允许携带的首部字段
Access-Control-Allow-Credentials 是否允许浏览器读取 response 的内容; 当用在 preflight 预检请求的响应中时,指定实际的请求是否可使用 credentials
Access-Control-Expose-Headers 指定 XMLHttpRequestgetResponseHeader 可以访问的响应头
Access-Control-Max-Age 指定 preflight 请求的结果能够被缓存多久

@better-pz
Copy link

壮哥,加个vx呗

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants