跨域资源共享 CORS
什么是CORS
在项目开发过程中,经常碰到跨域问题,同时也就不可避免的接触到cors
。
cors 是由 W3C 定义的,它的全称是------跨域资源共享 。但笔者第一次听到这个名称时仍然觉得云里雾里,并不知道他的具体是什么,笔者认为,实际上我们平常提到的cors
有两种不同的含义,我们不妨为它加上一些定语,让它读起来更加易懂:
- 跨域资源共享问题
这里的cors
指:
"受cors
规范限制的浏览器 向未满足cors
规范要求的服务器发送了跨域请求,因而无法得到响应。"
这样一种问题。
简单来说,就是当满足cors
规范的浏览器向不满足cors
规范的服务器发送请求时会受到限制,会拒绝掉服务器返回的响应,这种无法得到响应的情况被称为cors
情况。
- 跨域资源共享协议 或 跨域资源共享规范
这里笔者斗胆为该语境的cors
给出以下定义:
cors
规范是用来解决浏览器与服务器之间跨域问题的 http 请求规范。
再通俗易懂一点, 在这种语境下的cors
规定了为了浏览器安全,其在进行跨域请求时受到什么限制,服务器在响应跨域请求时应该怎么响应。
什么时候会遇到CORS
情况?
既然被称为跨域资源共享情况,肯定是在跨域过程中才会使用到,那么首先需要了解跨域的具体定义。
同源策略与跨域
同源
我们都知道一个 URL,例如https://www.example.com:80/helloworld?a=1?b=2#title
分为如下几部分:
- https ------ 协议
- www.example.com ------ 域名
- 80 ------ 端口
- /helloworld?a=1?b=2#title ------ 资源路径、参数等
当两个 URL 的协议、域名、端口完全相同时,我们称这两个 URL同源。
跨域
当两个 URL 不同源时却发起 http 请求时,我们称之为跨域,例如:
- 从
https://www.example.com:80
向https://www.example.com:81
发送请求时,发生了跨域。因为端口号不同。 - 从
https://www.example1.com:80
向https://www.example2.com:80
发送请求时,发生了跨域。因为域名不同。 - 从
http://www.example.com:80
向https://www.example.com:80
发送请求时,发生了跨域,因为协议不同。
CORS
情况与跨域的不同
我相信有很多人认为跨域与cors
情况是相同的,但笔者给出一个不同的观点,即cors
情况与跨域有如下不同:
概念不同
跨域是一个广义上的概念,是针对所有URL
提出的,即理论上可以对任意两个URL
进行判断是否跨域。 而cors
情况是一个针对浏览器安全提出的情况,因此只涉及到浏览器与服务器之间的URL
判断,即只有浏览器与服务器的URL
之间会出现cors
情况,服务器与服务器之间的URL
不会出现cors
情况。
表现不同
由概念不同延伸,当真正发生跨域时,并不一定会出现cors
情况。 例如:当 服务器 A 向 服务器 B 发送请求时(显然 服务器 A 与 服务器 B 的域名 并不相同),此次请求是跨域请求,但却并不是cors
情况。 因此笔者在上方给出的定义中特别强调了,不论是cors
情况还是cors
规范,一定是浏览器与服务器之间发生的故事。
综上所述
只有在浏览器 向服务器 发送跨域请求 时,才会发生cors
情况,此时的解决方案正是让服务器满足cors
规范。
CORS
的具体规范内容
在理解了cors
究竟是什么之后,再来看看cors
的具体规范内容。 前文已经提到过了,满足cors
规范的浏览器会受到一些限制,当服务器不满足cors
规范时,就无法实现浏览器与服务器的http
请求,接下来分别分析:
CORS
的预检机制
cors
为服务器提供了一种机制,即: cors
规范将 http 请求分为两种,分别是简单请求与复杂请求(该说法在最新的规范中已经弃用,此处只是将两种请求做一个区分)。 如果想知道cors
规范具体如何区分简单请求与复杂请求,请前往MDN。
简单请求
- 简单请求不触发预检机制,将直接发送完整
http
请求。 - 服务器端正常响应请求。
- 浏览器端查看服务器端的响应头是否满足
cors
规范,若不满足规范则拒绝接收数据。
复杂请求
- 当浏览器向服务器发送跨域请求时,会先进行一次预检,发送一个
option
方法的http
请求。 - 服务器端将对该请求的请求头进行判断,若该请求头不满足服务器端的规定,则不再发送携带数据的真实请求。
- 浏览器端接收到错误响应,报错。
CORS
对服务器端的规范
cors
为服务器端对于浏览器端请求的响应提供了一系列响应头:
Access-Control-Allow-Origin
规定在接受跨源请求时,允许该请求来自何处。Access-Control-Expose-Headers
规定在接受跨源访问时,浏览器端能拿到的额外响应头。Access-Control-Allow-Methods
规定在接受跨源访问时,允许浏览器发送的http
方法。
等等.....
cors
为服务器提供了许多可设置的响应头,此处不过多讨论具体代码,仅探讨原理,想了解可以到MDN学习。 (方便我以后再水一篇博客)
浏览器端受到的限制
上文提到了cors
为服务器提供的响应头,而cors
对浏览器端的限制是:
- 浏览器端向跨域服务器发送
http
请求时,会携带origin
等头,用来表明请求来自何处。 - 只有当服务器返回的响应包含正确的响应头才能成功接收到数据。
- 当服务器端返回的响应未包含正确响应头时,浏览器会主动拒绝接收该响应。
cors
同样为浏览器端提供了一系列请求头:
Origin
写明了发送跨域请求时,请求来自何处,即不包含路径等信息的源站 URL。Access-Control-Request-Method
用于将实际请求所使用的http
方法告诉服务器。Access-Control-Request-Headers
用于将实际请求所携带的标头字段告诉服务器。
同样,具体见mdn。
例子
当浏览器http://127.0.0.1:5678
向跨域服务器http://127.0.0.1:5700
发送http
请求时, 其请求头将自动添加一项origin: 'http://127.0.0.1:5678'
, 而服务器端未设置响应头Access-Control-Allow-Origin
或设置为Access-Control-Allow-Origin:http://127.0.0.1:8080
, 则浏览器将拒绝接收来自服务器的响应。
总结
cors
是前端开发中经常碰到的情况,当然解决方案也并不只是使服务器端配置满足cors
这一种,其他解决方案此处不讨论,未来总结后会把链接贴在这里。