前言
今天看到群里有人在聊前端的proxy代理
A: vue.config.js 中proxy中的 /api 不是代理了请求的后端的地址嘛,他是不是同时也代表这后端接口名中有/api才正确
B: 不对
B: vue.config.js 中proxy中的 /api 只是开开发环境使用,后端不需要做任何更改
B: api 是你本地起的node服务去请求后端,拿到结果给自己同域的的前端项目,这一切的根本原因是浏览器有跨域。服务端没有跨域
B: 你请求的 api 这个服务是你自己的代理服务,这个代理服务然后请求后端服务
B: 前端 proxy 代理 是开发环境,部署上线 需要前端部署 使用 ngxin 反响代理 把 api 代理出去
emm…看完也给我整懵了,B同学看起来是了解proxy,但是我觉得他给A同学讲解的时候有点答非所问~然后自己回想了下,虽然这东西用过了解过,但是如果让我讲解又不知道从何说起,于是决定做个笔记记录下。
使用场景
一般来说使用proxy配置项是为了解决本地开发产生的跨域问题,就比如前端发送一个请求 axios.get("/userInfo")
,浏览器中 http://localhost:8080/userInfo 去访问 https://www.leoleo.com/userInfo 这时候就会产生跨域。
实现原理
为什么通过配置proxy能解决跨域?
我们知道跨域其实是 浏览器的同源策略
导致的,http://localhost:8080/ 和 https://www.leoleo.com/ 显然是非同源的,即使 请求能访问到后端,但是浏览器也无法接收到返回的数据。
图中1、2代表没有经过代理的请求与响应,请求虽然到达了服务器,但是服务器返回的数据却会被浏览器拦截。
图中3、4代表经过代理转发后的请求与响应,代理是在本地开启的,所以域名与本地的一致,浏览器发送请求给代理 -> 代理去请求服务器 -> 服务器响应资源返回给代理 -> 代理把资源返回给浏览器 -> 浏览器拿到资源
Q: 代理和服务器域名不一致为什么可以接收服务器资源
A: 跨域是浏览器的限制,服务器之间没有跨域限制
基本配置
通过 proxy 配置项解决跨域问题
devServer: {
...
proxy: {
'/api': { // 标识字段:匹配访问路径中含有 '/api' 的路径
target: 'https://www.leoleo.com/', // 配置转发目标地址
pathRewrite: { // 路径重写配置
'^/api': ''
},
changeOrigin: true, // 控制服务器接收到的请求头中host字段的值
logLevel: 'debug', // 能打印出代理后的路径
},
'/api2': {
...
}
}
...
}
标识字段
'/api'
'/api2'
表示请求地址中需要包含了该字段就会对请求进行代理转发
target
目标地址,需要转发的目标地址
pathRewrite
重写请求路径,'^/api': ''
的意思就是把’/api’ 替换成空
logLevel
能在本地打印出代理后的路径,方便调试
changeOrigin
控制服务器接收到的请求头中host字段的值
假设,如果你的前端服务器是 http://localhost:8080 后端是 https://www.leoleo.com/
那么后端通过 request.getHeader(“Host”) 获取依旧是 http://localhost:8080
如果你设置了 changeOrigin: true,那么后端通过 request.getHeader(“Host”) 获取才是 https://www.leoleo.com/
结合上面的例子,如果想使用这段配置,那么需要在请求中加/api axios.get("/api/userInfo")
经过target的处理,请求路径已经变成了 https://www.leoleo.com/api/userInfo ,再经过pathRewrite的处理,请求路径已经变成了 https://www.leoleo.com/userInfo ,这时候就能正常访问服务器的地址了。
注意事项
一般项目中,前端都会用axios封装请求接口,还会有 .env[mode]
环境配置文件,比如
const service = axios.create({
...
baseURL: process.env.VUE_APP_BASE_API,
...
})
这时候就要注意了,如果你的 baseURL
已经配置了域名如 VUE_APP_BASE_API = 'https://www.leoleo.com/'
那么就算命中了代理配置,也不会走代理配置的!
可以改成 VUE_APP_BASE_API = '/api'
,这样发送请求的时候也只需要正常请求就可以了 axios.get("/userInfo")
总结
对了,最后回答A的问题,回答是:后端接口不一定需要有/api。如果有,那么pathRewrite就不用配置了,如果没有,那就用pathRewrite去掉/api。