什么是跨域
跨域全称为Cross-Origin Resource Sharing,意为跨域资源共享,是一种允许当前域(domain)的资源被其他域(domain)的脚本请求访问的机制,通常由于同源安全策略,浏览器会禁止这种跨域请求。
而我们所说的跨域问题是因为违反了浏览器的同源安全策略而产生的。
同源安全策略
同源安全策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。
同源是指协议、域名、端口三者相同,即使两个不同的域名指向同一个ip地址也是非同源。
注意:
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。
解决跨域的方法
jsonp
jsonp:json with padding
原理:利用 script 标签没有跨域限制的特点,通过动态生成 script 标签,指定 src 属性的方式加载跨域资源。
实现流程:
- 声明一个回调函数,其函数名当作参数值传递给跨域请求数据的服务器,函数形参为要获取的目标数据,即服务器返回的data
- 创建一个script标签,把跨域的api数据接口赋值给src属性,通过问号传参的方式加上函数名。比如 ?callback=getDatas
- 服务器接收到请求后,把传递进来的函数名和它需要的数据拼接成一个函数调用形式的字符串,比如 "getDatas('目标数据')"
- 最后服务器通过HTTP协议返回给客户端,解析执行函数。
理解:全局定义一个函数 getDatas,并通过script标签的src属性把函数名发到后端,后端收到函数名后,把数据填充进括号里,返回给前端,比如字符串 "getDatas('目标数据')",前端得到字符串后,因为是script标签,当作js文件进行解析,发现是个函数调用,执行函数后数据就得到了。
要求:JSONP需要服务器进行支持。
缺点:只支持 GET。
应用场景:有些第三方数据接口可能会使用jsonp解决跨域问题,工作中基本不用。
配置后端:CORS
浏览器是否启用同源安全策略是根据后端响应的 Access-Control-Allow-Origin 响应头来定的,所以配置后端是最直接的一种方法,也是工作中常用的解决方案。
支持:支持所有的主流浏览器、IE9+。
操作:在服务器端进行配置,加一个 Access-Control-Allow-Origin 响应头
res.header('Access-Control-Allow-Origin', '*')
如果这个字段的值是"*",那么会允许所有请求,如果是一个域名,那么浏览器就不会对这个域名下的请求的响应进行拦截。
根据开发接口的语言和库的不同,配置 Access-Control-Allow-Origin响应头的方法也不同,如果使用的是 node.js 和 express,那么可以添加 cors 中间件:
const express = require('express')
const app = express()
const cors = require('cors')
app.use(cors())
cors 默认会允许所有跨域请求,如果要限制指定域名,可以给它的origin配置项传递一个字符串或数组,用于指定一个或多个允许跨域的域名:
app.use(cors({
origin: ['http://domain1.com', 'http://domain2.com']
}))
中间服务器代理
前端部署地址:127.0.0.1:8000
中间服务器地址:127.0.0.1:8000
目标服务器地址:127.0.0.1:8888
服务器请求服务器的数据没有跨域问题
正向代理
正向代理是代理服务器对客户端进行代理,为客户端收发请求,使得真实客户端对目标服务器不可见。
应用:科学上网
反向代理
反向代理是代理服务器对目标服务器进行代理,为目标服务器进行收发请求,使得真实服务器对客户端不可见。
反向代理不需要客户端进行任何设置。
应用:Nginx
配置前端
在前端开发环境中,配置代理,中转请求。因为跨域是浏览器的安全策略,如果脱离浏览器发送请求是不会受到同源安全策略的影响的,所以可以使用一个中间服务器对浏览器进行代理。
一般的前端脚手架工具都支持配置代理,例如 vue cli、vite、create react app等。
1. vue cli 配置正向代理
vue cli 提供的 webpack-dev-server 开发服务器支持设置代理,可以在 vue.config.js 文件中配置devServer配置项下的proxy配置项,把对/api路径的请求代理转发到真实的后端服务器路径,再根据需要对转发后的URL进行改写。
module.exports = {
devServer: {
// 设置代理
proxy: {
"/api": { // 类似于前缀
target: 'http://127.0.0.1:8888/api/xxx', // 目标服务器地址
wx: true, // 是否启用 websocket
chageOrigin: true, // 开启代理:在本地会创建一个虚拟服务器,然后发送请求的数据,
// 同时接收响应的数据,这样服务端和服务端之间进行数据交互就不会有跨域的问题
pathRewrite: {
"^/api": "/"
}
}
}
}
}
2. vite 配置正向代理
vite 提供的开发服务器支持设置代理,可以在 vite.config.js 文件中配置server配置项下的proxy配置项,把对/api路径的请求代理转发到真实的后端服务器路径,再根据需要对转发后的URL进行改写。
export default defineConfig({
server: {
// 设置代理
proxy: {
"/api": { // 配置需要代理的路径,作用类似于前缀
target: 'http://127.0.0.1:8888/api/xxx', // 目标服务器地址
wx: true, // 是否启用 websocket
chageOrigin: true, // 允许跨域
rewrite: (path) => path.replace(/^\/api/, "/") // 重写代理路径
}
}
}
})
3. create react app 配置正向代理
注意:
配置Proxy理后,注释掉 axios.defaults.baseURL
// axios.defaults.baseURL='http://127.0.0.1:8888/api/xxx'
注意:配置proxy的方式只是在开发时使用的,在生产中就不能用了。