关于跨域和解决方案
跨域和代理
什么是跨域
是一种由浏览器强制实施的安全机制。
指浏览器出于安全考虑,限制网页脚本向不同源的服务器发起请求。
这是浏览器的同源策略导致的限制。
同源策略: 由协议+域名+端口号组成,要求三个完全相同
- 协议:如 http 与 https 不同源。
- 域名:如 example.com 与 api.example.com 不同源。
- 端口:如 80 与 8080 不同源。
举例:
如果一个网页(来自 http://localhost:xxxx)试图向另一个域名(https://api-xxxx.com)发送请求,浏览器会先发一个 OPTIONS 请求(预检请求)询问服务器是否允许。
后端需要在它的响应头(Response Headers)中加入像 Access-Control-Allow-Origin: http://localhost:xxxx 这样的字段,告诉浏览器:“我允许来自这个前端的请求”。
跨域的常见场景
- 前端域名 https://example.com 请求后端接口 https://api.example.com。
- 本地开发时前端 http://localhost:3000 请求后端 http://localhost:8080
- 使用 http 协议访问 https 接口。
跨域的解决方案
不管是运行在本地 / 测试 / 生产环境,都和后端接口的地址不同源,所以直接发送请求一定会跨域。
以下有不同的方案来解决跨域问题。
1、CORS(跨域资源共享)
后端通过设置响应头允许跨域请求,例如
请求:
使用绝对URl(直接请求后端)
// 在axios中直接使用完整URL
axios.get('https://api-xxxx/system/xxxx').then(response => {// 处理响应});
这么写的比较少,一般会做一些基础配置,然后使用相对路径
const api = axios.create({baseURL: 'https://api-xxxx.com', // 基础地址直接是后端timeout: 30000,
});// 使用相对路径,最后被发送到 https://api-xxxx.com/system/xxxx
axios.get('/system/xxxx').then(response => {// 处理响应});
流程:
虽然前端没有使用代理,但是
- 前端直接请求 https://api-xxxx.com/system/xxxx
- 浏览器识别到这是跨域请求,发送预检OPTIONS请求
- 后端正确配置了CORS
- 浏览器看到后端允许跨域,放行
2、JSONP
通过 script 标签绕过跨域限制,仅支持 GET 请求。
实际的vue项目中不会用这种方式
3、代理服务器
在开发工具(如 Vite、Webpack)中配置代理
告诉前端的开发服务器(如 Vite、Webpack):“所有以 /api 开头的请求,别直接发给我的后端,你先帮我转发一下”。
流程:
- 你在前端代码中写了一个相对路径的请求:axios.get(‘system/xxx’)
- 浏览器会认为这个请求是发给http://localhost:xxxx(当前前端页面所在的域名)的
- 但你在vite.config.js中配置了代理,vite开发服务器会拦截这个发给localhost的请求
- vite开发服务器会悄悄将这个请求转发到配置的后端目标地址
- 收到后端返回的数据后,vite再把它交给前端
- 对浏览器而言,它只知道它向localhost请求并收到了响应,完全没有触发跨域限制,因为对它来说,这是同源请求
// vite.config.js
server: {port: env.VITE_PORT, // 端口号host: "0.0.0.0",open: env.VITE_OPEN === 'true',proxy: {['/api']: {target: env.VITE_BASE_URL,changeOrigin: true,rewrite: (path) => path.replace(new RegExp(`^/admin-api`), ''),},},
},
生产环境注意: 这种代理只在开发环境(npm run dev)下有效,当你构建生产版本时,就失效了,需要直接请求后端API的绝对URL,或者配置生产环境的反向代理(比如Nginx)