跨域
同源策略
若页面的源和页面运行过程中加载的源不一致时,出于安全考虑,浏览器会对跨域的资源访问进行一些限制
- 源=协议+主机+端口,两个源相同,称之为同源,两个源不同,称之为跨源或跨域
解决办法:代理、JSONP、CORS
代理
- 适用场景:生产环境不发生跨域,但开发环境发生跨域
- 处理:配置devServer-proxy或者nginx ==>了解webpack的文档
module.exports = { devServer: { proxy: { // 配置代理 "/api": { // 若请求路径以 /api 开头 target: "http://dev.taobao.com", // 将其转发到 http://dev.taobao.com } } } }
location / { proxy_pass http://localhost:3001/; // 当前运行工程 } location /api/ { proxy_pass http://dev.taobao.com/; // 请求地址 }
JSONP
- 只支持
GET
请求,需要前后端配合 - 原理:当需要跨域请求时,不使用AJAX,转而生成一个script元素去请求服务器,由于浏览器并不阻止script元素的请求,这样请求可以到达服务器。服务器拿到请求后,响应一段JS代码,这段代码实际上是一个函数调用,调用的是前端预先生成好的函数,并把浏览器需要的数据作为参数传递到函数中,从而间接的把数据传递给前端
// 服务端
app.get(
"/test",
(req, res)=>{
var callbackName = req.query.callback;
var func = callbackName + 'hello!'
res.send(func)
}
)
// 前端
<script>
test(data) {
// 打印内容:data:hello!
console.log('data:', data)
}
</script>
<script src="http://dev.taobao.com?callback=test"></script>
CORS-跨域资源共享
- 思路:如果浏览器要跨域访问服务器的资源,需要获得服务器的允许
- 三种交互模式:简单请求、需要预检的请求、附带身份凭证的请求
- 简单请求
- 满足下面三种情况
- 是
GET
、POST
、HEAD
请求 - 请求头仅包含安全的字段,如
Accept
、Accept-Language
、Content-Language
、Content-Type
、DPR
、Width
等
- 如果请求头包含Content-Type
,仅限text/plain
、multipart/form-data
、application/x-www-form-urlencoded
- 当浏览器判定请求是简单请求时
- 请求头中会自动添加
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
:告诉浏览器,多少秒内,对于同样的请求源、方法、头,都不需要再发送预检请求了
- 浏览器发送真实请求
- 服务器响应真实请求
- 有以下三种特征
- 附带身份凭证的请求
- 会在请求头中添加
cookie
- 服务端需要在响应头中添加
Access-Control-Allow-Credentials: true
,需要服务端配合- 另外需要注意,对于附带身份凭证的请求,服务器不得设置
Access-Control-Allow-Origin: *
- 另外需要注意,对于附带身份凭证的请求,服务器不得设置
- 会在请求头中添加
- 补充
- 在跨域访问时,JS 只能拿到一些最基本的响应头,如果要访问其他头,需要让服务端设置响应头Access-Control-Expose-Headers
,把允许浏览器访问的头放入白名单
参考文章:https://www.jb51.net/article/254822.htm