前言
前端开发过程中,跨域是不可避免会出现的问题,一般我们使用代理的比较多,实际上不止有代理能够解决,还有更为常见的 cros 方案,并且这里也会简单介绍跨域的特征,以及从哪里解决入手解决问题的
跨域与策略
跨域问题就是前端服务与后端服务部署的域名不一致,用户使用浏览器下载前端代码时了解到了前端服务地址,在网络请求访问服务端地址时,发现访问服务端域名与前端的域名不一致,此时会自动在请求头中添加 Origin
字段,服务器发现不是同源,则默认直接拒绝访问,引出出现了跨域
这里解释一下跨域:域名不一样即为跨域
以 https://www.baidu.com
为例
http://www.baidu.com
:跨域, 协议不同(一个https,一个http)https://www.taobao.com
: 跨域,主域名不同https://tieba.baidu.com
: 跨域,子域名不同(一般的通配符证书指的是多个子域名)https://www.baidu.com:3000
:跨域,端口号不同https://www.baidu.com/home.html
: 不跨域,同源,可以理解为同一个项目不同路径下的子页面
跨域解决方案思路
- 通过浏览器的特性,
绕开添加 origin 字段
的方式,这样后端没办法识别是否跨域(使用postman
的时候碰不到就是这个原因),但使用浏览器加载的前端页面就没办法主动绕开
了,但是有个漏洞就是 JSONP 方案,不安全,且仅支持get方法,因此也不推荐 - 服务端就是收到了 origin 不一致的情况,仍然允许请求,这就是 CROS 方案
- 设置代理,将
前端与代理服务部署到同一个域名下
,前端通过代理(中间人)访问后端,也就是前端的请求,代理会转发给后端,可以认为浏览器将代理当成了后端,因此认为同源,则避免了此类问题
目前比较常用的几种跨域解决方案
:
- 前后端放置到一个域名下,但是实际开发过程中很不实际(一些大厂可以忽略,甚至一些大厂也不是所有部门都这么做)
- 后端设置允许跨域,即不采用同源策略,或者设置白名单(实际就是 CROS 方案)
- 部署后设置 Nginx 代理,或前端直接设置代理,将前端服务与代理服务运行到统一域名下,即使用中间服务器代理前端访问接口:前端 <=> 代理服务器 <=> 后端
JSONP(不推荐)
JSONP 的核心原理是利用了 <script>
标签的 src
属性不受同源策略限制的特点。
通过在页面中动态创建 <script>
标签,向服务器请求一个 JSON 数据,并在请求的 URL 中添加一个回调函数名作为参数。
服务器收到请求后,会将 JSON 数据包装在这个回调函数中返回给客户端。
客户端的 <script>
标签会执行这个返回的 JavaScript 代码,从而调用回调函数并将 JSON 数据作为参数传入,实现数据的跨域获取。
js
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
</head>
<body>
<script>
function handleResponse(data) {
console.log('Received data:', data)
}
const script = document.createElement('script')
script.src = 'http://www.baidu.com?callback=handleResponse'
document.body.appendChild(script)
</script>
</body>
</html>
//服务端response需要拼接成函数脚本,便于客户端执行
const response = `${callback}(${JSON.stringify(data)})`;
res.setHeader('Content-Type', 'application/javascript');
res.send(response);
CORS(Cross-Origin Resource Sharing)
CORS 是一种现代的跨域解决方案,它通过服务器设置响应头来允许跨域请求。当浏览器检测到请求是跨域的,会自动在请求头中添加 Origin
字段,服务器根据这个字段来判断是否允许该请求
js
//后端设置允许所有源即可
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
//或者像我前面设置的nestjs项目似的允许跨域
app.enableCors()
代理
在开发环境中,可以使用代理服务器来解决跨域问题
代理服务器与前端代码运行在同一域名下,前端将请求发送给代理服务器,代理服务器再将请求转发到目标服务器,并将响应返回给前端
下面是常见的 http-proxy-middleware中间件、nextjs代理、vite代理
js
//setupProxy.js
// 配置代理中间件,以进行连接、表达、浏览器同步等。
const { createProxyMiddleware } = require("http-proxy-middleware");
// 配置代理服务
const apiProxy = createProxyMiddleware("/api", {
target: 'http://172.27.106.56:5000/',
ws: true,
// changeOrigin: true,
// pathRewrite: { '^': '' },
});
module.exports = function (app) {
app.use(apiProxy);
}
next.config.mjs
js
//next.config.mjs
rewrites() {
return [
// 当请求路径符合 /api 时,将请求转发到代理服务器
{
source: '/api/:path*',
destination: 'http://192.168.1.1:4000/api/:path*',
},
];
},
vite.config.ts
js
server: {
//代理
proxy: {
'/api': {
// 这里填写后端地址
target: 'http://192.168.1.1:4000', //测试服务
changeOrigin: true,
},
},
},