本地开发代理更改origin和响应cookie(webpack)
问题场景
- 后端api服务开启了跨域校验
- 并且登录凭据由接口响应设置到cookie(并且为HTTP-ONLY类型),cookie只对线上环境的域名生效
如果前端开发时使用的是localhost或者本地回环地址,前端开发服务简单的去代理接口请求是不行的,因为服务端的set-cookie响应头设置cookie的domain是正常域名(www.somedomain.com)。
结果就是localhost发出的请求无法携带上www.somedomain.com的cookie,也就无法正常登录和调用接口。
解决方案
参见webapck文档:开发服务器使用功能强大的 http-proxy-middleware 软件包。 查看其 documentation 了解更多高级用法。
主要是2个关键点:
- 请求转发时,要替换header里的origin、host、referer
- 响应转发时,要把cookie的domain配置改成localhost或则本地回环地址,webpack使用的是
cookieDomainRewrite配置。
vue.config.js配置(基于webpack)
// 【可修改】本地开发-代理接口的目标的 ip 地址url(可按需修改,如http://192.168.100.11、http://192.168.100.43)
const API_SERVER_IP_URL = 'http://192.168.100.11';
// 【以下内容看不懂不要改】
// 本地开发用的域名
const LOCAL_DEV_HOST = 'localhost';
// 用于替换请求头里的host和origin:
const REQUEST_HEADER_HOST = 'target.domain.com';
const REQUEST_HEADER_ORIGIN = `http://${REQUEST_HEADER_HOST}`;
/**
* 代理请求时,替换请求头里的host和origin
* - 后端接口只认生产域名,如果host、origin不是生产域名,接口会返回404。
*/
const onProxyReq = function(proxyReq, req, _res) {
proxyReq.setHeader('host', REQUEST_HEADER_HOST);
proxyReq.setHeader('origin', REQUEST_HEADER_ORIGIN);
const { headers } = req;
const { referer, host } = headers;
proxyReq.setHeader('referer', referer.replace(new RegExp(host, 'g'), REQUEST_HEADER_HOST));
};
/**
* 如果接口响应中重定向目标不是本地开发域名,则替换重定向链接的域名为本地开发域名,防止开发到一半跳到线上环境
*/
const onProxyRes = (proxyRes, req, _res) => {
const { location } = proxyRes.headers;
if (location) {
console.log(`检测到接口重定向,重定向目标地址:${location},来源:${req.url}`);
//
if (location.startsWith('http://') && !location.startsWith(`http://${LOCAL_DEV_HOST}`)) {
let url = new URL(location);
const whiteList = []; // TODO
if (whiteList.includes(url.hostname)) {
// 在白名单里,则不改重定向链接的域名
return;
}
url.hostname = LOCAL_DEV_HOST;
url = url.toString();
console.log(`-重定向地址已替换:${location} -> ${url}`);
proxyRes.headers['location'] = url;
}
}
};
module.exports = {
publicPath: '/xxx/',
devServer: {
port: 80,
disableHostCheck: true,
overlay: {
warning: true,
errors: true,
},
proxy: {
'/api': {
target: API_SERVER_IP_URL,
changeOrigin: true,
ws: true,
// 将接口响应中的set-cookie中的domain修改为本地的host
cookieDomainRewrite: LOCAL_DEV_HOST,
onProxyReq,
onProxyRes,
},
'/a': uth{
target: API_SERVER_IP_URL,
changeOrigin: true,
ws: true,
// 将接口响应中的set-cookie中的domain修改为本地的host
cookieDomainRewrite: LOCAL_DEV_HOST,
onProxyReq,
onProxyRes,
},
},
},
};webpack.dev.config.js和vue不太一样,可以完整的使用http-proxy-middleware的特性,所以proxy部分可以简写:
...
proxy: [// 可以使用数组配置
{
context: [ 'api', 'auth' ],
target: API_SERVER_IP_URL,
changeOrigin: true,
ws: true,
// 将接口响应中的set-cookie中的domain修改为本地的host
cookieDomainRewrite: LOCAL_DEV_HOST,
onProxyReq,
onProxyRes,
},
]