前言
大家都知道,利用webpack、vite的proxy可以解决开发环境的跨域问题。
但是在真实开发场景下,我们可能不仅要面对跨域问题,还有可能面对动态header的情况。
让我们来看如下案例
案例
强盛集团开发了一套多店铺的H5商城系统,此时小安 小龙 小虎,都想利用这个系统开一个线上商城,我们如何区分他们的店铺呢?
聪明的同学肯定已经想到了答案,用二级域名进行区分
小安 -> xa.shop.com
小龙 -> xl.shop.com
小虎 -> xh.shop.com
接下来让我们把视角聚焦到强盛集团的技术部门。
面对这样的多店铺商城系统,开发环境肯定无法用ip直接访问了,因为ip无法识别具体是什么店铺。
这个问题其实也很好解决,修改本地host即可
127.0.0.1 xa.shop.com
127.0.0.1 xl.shop.com
127.0.0.1 xh.shop.com
假设我们开发环境的端口是8082,我们想在开发环境访问小安的店铺,则通过xa.shop.com:8082
进行访问。
直到某一天,安全部门发现了沙海集团的的scrf恶意攻击,决定限制该产品请求发起方的Origin Header与Referer Header,并且限制了必须是80端口。
这两个请求头的含义是标记来源域名,可以起到防止scrf攻击的目的。
此时前端开发就麻烦了,因为在开发环境,我们的Origin Header与Referer Header都是x.shop.com:8082,这会被服务端识别为不合法的请求来源,同时因为浏览器安全限制,前端是不具备直接修改referer头的能力, 除非将项目端口号改为80端口,但是这并不是一个好办法。
如果你是强盛集团的前端开发,你会怎么解决以上问题呢?
后端高某强提供的思路
后端高某强这时候提供了一个想法,通过本地nginx代理8082端口就好了呀。
- 在开发机器本地启动一个nginx
- 通过nginx将x.shop.com指向127.0.0.1:8082
- 同时配合host的修改,实现开发环境去端口的诉求。
后续,我尝试了这个方案,确实是可以实现的,也在团队中推广并使用了一段时间;
但是长期使用下就暴露了一些问题
- 每次新增一个站点,都需要同时增加host、nginx中的配置,流程复杂。
- 并不是每个前端都了解nginx,初级开发非常容易出问题,增加团队内耗。
proxy解决方案
Vite解决方案
直到某一天,我在vite的文档中突然发现一个细节,server.proxy的实现依赖node-http-proxy,而这个库具备设置请求头的能力
如果是这样,我是否可以在开发环境通过proxy代理请求接口,同时覆写Origin Header与Referer Header的方式来解决我们遇到的多域名+端口限制问题呢?进而在开发环境规避掉nginx。
通过vite的问题可以了解到参数configure可以编写http-proxy相关逻辑,再结合http-proxy文档,我们便可以完成相关代码。
server: {
// .....
proxy: {
'/client': {
target: 'https://api.xxxx.com', // 需要代理的地址
changeOrigin: true,
secure: true, // 如果是https接口,需要配置这个参数
rewrite: (path) => path.replace(/^\/client/, ''),
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq, req, res) => {
// req是当前真实请求的地址 开发环境为:a.shop.com:8082
let host = req.headers.host!.split(':')[0] // a.shop.com 动态获取当前请求地址,并去除端口
proxyReq.setHeader('referer', `http://${host}`)
proxyReq.setHeader('origin', `http://${host}`)
})
},
},
},
// .....
},
测试结果符合预期,web端请求被proxy代理,并在代理请求中完成了端口的去除,符合了服务端对Origin Header与Referer Header的要求。
Webpack解决方案
vite测试成功后,我们便开始对webpack的vue2.x项目proxy动态headers进行评估;通过webpack4的文档,我们可以了解到webpack4的proxy是基于http-proxy-middleware 进行实现。
接下来我们也顺利在http-proxy-middleware文档中找到相关配置
我们基于webpack与http-proxy-middleware的文档,就可以很顺利的做产出了。
devServer: {
// ....
proxy: {
'/client': {
target: 'https://api.xxxx.com', // 需要代理的地址
changeOrigin: true, //是否跨域
secure: true, // 如果是https接口,需要配置这个参数
pathRewrite: { '^/client': '' },
onProxyReq: (proxyReq, req, res) => {
let host = req.headers.host.split(':')[0]
proxyReq.setHeader('referer', `http://${host}`) //添加请求头
proxyReq.setHeader('origin', `http://${host}`) //添加请求头
},
},
},
// .....
},
项目配置完成后,我们便可以在开发环境利用proxy的动态headers完成a.shop.com:8082正常访问线上端口了,只需要在本地配置host即可。
结语
高某强了解到前端部门使用proxy + 动态headers方案后,连连称赞,表示请我去他家吃鱼。
如果你也遇到了类似的问题,快来试试proxy的解决方案吧~