跨域常见的解决方法
之前有被人问到过跨域这块的东西,当时答得有点模糊,再回顾一下
>跨域概念
浏览器中有一个安全策略叫同源策略,意思是协议、主机、端口必须相同,如果其一不同,则称之为跨域,对于跨域的请求,出于安全考虑,浏览器会对其访问进行一些限制
Ajax
对于传统ajax,浏览器默认不允许其发送跨域请求,但是有三种方案可以解决
- 代理
代理适用的场景是:生产环境不发生跨域,但开发环境发生跨域
比较常见的是通过webpack集成的 devServer 实现代理去解决跨域问题
1 | // vue 的开发服务器代理配置 |
- JSONP
通过前后端配合,利用 script 标签不受同源策略限制去令服务端响应一段JS代码,将需要返回的数据作为参数传入该代码中,客户端再负责调用,类似ajax的回调函数。
但JSONP有一个明显的问题就是只能发送Get请求
- CORS
CORS
是基于http1.1
的一种跨域解决方案。全称叫跨域资源共享
总体思路是:如果浏览器要跨域访问服务器的资源,需要获得服务器的允许
针对不同的请求,CORS 规定了三种不同的交互模式,分别是:简单请求、需要预检的请求、附带身份凭证的请求。
当请求方法属于get、post、head;请求头仅包含安全的字段;请求头如果包含Content-Type,仅限 text/plain
、multipart/form-data
、application/x-www-form-urlencoded
;同时满足上面三个条件后则判断为简单请求。
常见的安全字段如下:
Accept
Accept-Language
Content-Language
Content-Type
DPR
Downlink
Save-Data
Viewport-Width
Width
当浏览器判断某个请求为简单请求后,会在请求头中自动添加 Origin 字段,用以告诉服务器,是哪个源地址在跨域请求,服务器在收到请求后,需要添加 Access-Control-Allow-Origin
用以表示开放的权限(* 表示允许所有,也可以写具体的地址表示只允许该源下的请求访问)
对于需要预检的请求(不符合上述条件),浏览器会先发送预检请求,如果服务器允许访问,则浏览器发送真实请求,最后服务器完成真实请求的响应
预检请求有以下特征:
- 请求方法为
OPTIONS
- 没有请求体
- 请求头中包含
Origin
:请求的源,和简单请求的含义一致Access-Control-Request-Method
:后续的真实请求将使用的请求方法Access-Control-Request-Headers
:后续的真实请求会改动的请求头
对于预检请求的响应,不需要请求体,只需要在响应头中添加
Access-Control-Allow-Origin
:和简单请求一样,表示允许的源Access-Control-Allow-Methods
:表示允许的后续真实的请求方法Access-Control-Allow-Headers
:表示允许改动的请求头Access-Control-Max-Age
:告诉浏览器,多少秒内,对于同样的请求源、方法、头,都不需要再发送预检请求了
默认情况下,ajax 的跨域请求并不会附带 cookie,这样一来,某些需要权限的操作就无法进行,不过可以通过简单的配置就可以实现附带 cookie,xhr通过 withCredentials = true
配置,fetch 通过 init 参数对象中的 credentials
配置。这样一来该请求就是一个附带身份凭证的请求,会在请求头中添加 cookie
字段。服务器需要在响应头中添加 Access-Control-Allow-Credentials: true
即可
**对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为*
**。
跨域常见的解决方法