同源策略
同源策略是浏览器的一种自我保护行为。用于限制在Web浏览器中加载和执行来自不同源(来源)的资源。所谓的同源指的是:协议,域名,端口均要相同。
浏览器中大部分内容都是受同源策略的限制的,除了以下三个标签:
<img src="..." />
<link href="..." />
<script src="..."></script>
跨域
但有些时候,我们又确实需要访问一些跨域资源,那怎么办呢? 那就需要跨域!所谓
跨域就指的是去向一个非本源的目标地址发送请求的过程!跨域的解决方案如下:
(1) jsonp 【前后端配合】
jsonp实际上就是通过 script 标签的 src 去请求数据,因为 script 标签的请求不会被同源策略所限制!再通过 callback 函数实现对数据的获取!(这种方式需要后端进行配合,后端在前端进行对应请求的时候返回对应的jsonp格式)
前端写法如下:
<script type="text/javascript">
function callbackFunction(result, methodName) { ///result 指向对应数据
}
</script>
<script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script>
(2) CORS 【后端】
CORS跨域资源共享,通过服务器的响应头进行配置!即服务器自身指定允许哪些域可以对自己进行访问!
配置的值可以是固定的白名单ip或者通配符,可以用通配符"*",代表接受所有请求。
CORS 对于简单请求和复杂请求的处理方式不同!
简单请求: 【mdn定义的简单请求就是不会触发 cors 预检的请求】
- 请求方法为 :GET、HEAD、POST
- 请求头只能设置:Accept、Accept-Language、Content-Language、Content-Type
- 且 Content-Type 的值只能是: application/x-www-form-urlencoded、 multipart/form-data、 text/plain
后端只需要配置响应头Access-Control-Allow-Origin
'Access-Control-Allow-Origin':'xxx'
预检请求:
预检请求是指在发送跨域请求前,浏览器会先发送一个OPTIONS请求,询问服务器是否允许该跨域请求。如果服务器返回的响应头中包含了CORS相关的设置,并且服务器认为该跨域请求是合法的,浏览器才会发送真正的请求。这个预检请求的过程就是CORS中的预检过程,也被称为CORS预检。
- 请求方法为:PUT、DELETE、CONNECT、OPTIONS、TRACE
- 请求头中设置了除了上述的任意多项
Content-Type设置了简单请求不允许的值,如常用的application/json
后端需要配置的响应头就要多一点了:
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
-
Access-Control-Allow-Methods代表可接受methods
-
Access-Control-Allow-Headers代表可接受的headers修改
-
Access-Control-Max-Age代表预检的残留时间,代表预检之后可以免预检的时间
(3) 代理
3.1 webpack-dev-server
在webpack.config.js中配置代理如下:
devServer: {
// ...其他配置
proxy: {
'/api': {
target: 'http://api.example.com/', // 要代理到的地址
pathRewrite: { '^/api': '' }, // 将/api开头的路径去掉 changeOrigin: true, // 是否跨域
},
},
}
3.2 node.js 中间件 http-proxy-middleware
在代码中配置如下:
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const app = express();
app.use('/api', createProxyMiddleware({
target: 'http://api.example.com',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}));
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
3.3 Nginx 反向代理
(4) 解决方案对比
- jsonp 只支持get请求,无法支持复杂的请求
- webpack-dev-server 只支持线上环境
- node 、nginx 相对较好,当然实现起来也更复杂!