一.什么是跨域
1.简介
跨域分为开发跨域(开发环境跨域)和线上跨域(生产环境跨域):
开发环境跨域:开发阶段前后端工作站不同,所以ip地址不同,请求数据必然出现跨域问题;
生产环境跨域:一个网站关联多台服务器,构成一个完整的生产服务器集群。不同的服务器之间通过地址进行通信,就算在局域网中,端口地址也是不一样的,就会产生跨域问题。
2.同源策略
跨域问题其实就是浏览器的同源策略所导致的。同源策略是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到攻击。所谓同源是指"协议+域名+端口"三者相同(注:即便两个不同的域名指向同一个ip地址,也非同源)不同源之间相互请求资源,就算作“跨域”。
注:跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
但是有一些标签是允许跨域加载资源:
<img src="xxx">
<link href="xxx">
<script src="xxx">
一.解决跨域
1.JSONP (线上跨域解决方案)
(前端+后端共同解决)
JSONP 跨域主要就是利用了 script 标签没有跨域限制的这个特性。
通过script标签src属性,发送带有callback参数的get请求,服务端将返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,拿到callback函数返回的数据:
<script type="text /javascript">
window.jsonpCallback = function (res) { console.log(res); }
</script>
<script src="http://xx/api/jsonp?msg=abc&callback=jsonpCallback" type="text/javascript"></script>
// 相应后端实现
app.use(async (ctx, next) => {
if (ctx.path === "/api/jsonp") {
const { callback, msg } = ctx.query;
ctx.body = `${callback.stringify({ msg })})`;
return;
}
});
jsonp的缺点:只能发送get一种请求。
2 跨域资源共享(CORS)(线上跨域解决方案)
(服务端解决的方式)
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器发出请求,从而解决了Ajax只能同源使用的限制。
CORS需要浏览器和服务器同时支持。目前,所==有浏览器都支持该功能,IE浏览器不能低于IE10。
我们只需要在后端代码上增加一个跨域请求响应头:Access-Control-Allow-Origin
例如php中的 header(Access-Control-Allow-Origin:*) *表示所有请求地址都允许跨域响应。
3.代理服务器
vue项目开发环境跨域问题
1.在vue.config.js里配置
// 跨域的代理中转服务器服务
proxy: {
"/api":{ // /vue代理target
target: 'http://10.1.XXX.XXX:8088', // 后端接口的根目录
// secure: true, // 如果是 https ,需要开启这个选项,http为false
changeOrigin: true, // 是否跨域
pathRewrite: { // 是否重写路径,看代理前端路径是否与后端路径一致
'^/api':'', //将所有含/api路径的,去掉/api转发给服务器
}
}
},
2.react项目开发环境跨域问题
npm i http-proxy-middleware -S
项目src中新建文件setupProxy.js,名字不能更改,必须是这个
//setupProxy.js内容
const proxy = require('http-proxy-middleware')
module.exports = function(app) {
app.use(
proxy.createProxyMiddleware('/api', {
target: process.env.REACT_APP_BASE_URL, //你需要访问的地址
changeOrigin: true,
// secure: false,
pathRewrite: {'^/api': ''}
})
)
}
3.nginx代理
server {
listen 8888;
server_name localhost;
location /api/ {
proxy_pass http://targetserver.com/api/;
add_header Access-Control-Allow-Origin *;
# 其他配置
}
}
在上面的配置中,/api/ 是要跨域访问的接口路径,http://targetserver.com/api/ 是目标服务器的接口地址。当请求到达 Nginx 后,Nginx 会将请求代理到目标服务器,同时在响应头中添加 Access-Control-Allow-Origin 信息,允许所有源跨域访问。
4.Websocket方式解决跨域
使用Websocket也可以解决跨域问题,因为WebSocket本身不存在跨域问题,所以我们可以利用webSocket来进行非同源之间的通信,
二.跨域请求携带cookie
默认情况下是跨域是不会携带cookie的,例如:a.com 网站请求 b.com 的接口,这个时候不会把a.com这个域名下的 cookie 携带上。如果需要携带,则需要做一下配置
1.前端配置
XMLHttpRequest发请求需要设置
withCredentials=true
fetch 发请求需要设置
credentials = include
axios发请求配置:
axios.defaults.withCredentials = true
2.服务端配置
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: [特定域名] // 不能设置为 “” 或 *,而要设置为客户端发送请求时的IP地址
因为最新版本谷歌浏览器 samesite 属性默认是 lax,lax 模式在很多情况都是不允许跨域携带cookie,所以必须要把 samesite设置为 none, 但是设置为 none 有一个要求,就是必须 secure 属性为 true,也就是必须使用 https 。
设置 cookie 增加配置
sameSite: 'none'
secure: true