在使用http-proxy-middleware的时候,有一个配置是“changeOrigin”,通过名字来看这个字段是用来控制是否修改origin的,但是实际使用下来,你会发现,当设置为true的时候,header中的origin的值并不会修改,而是修改的host的值。
为什么修改是host呢?那么要修改origin请求头,又应该如何处理呢?下面我就一步一步展开研究一下。
去看一下http-proxy-middleware的源码
不知道怎么去看源码?
我带你一步一步去找找看。
首先工程中安装了http-proxy-middleware,那么在你的node_modules目录下面就会找到http开头的几个目录
根据名字,我们猜测应该在 http-proxy 开头的几个文件中,那么范围就很小了,就可以挨个去找一下。
最后,我们找到,这个的相关源码是在http-proxy包中的common.js中。
if (options.changeOrigin) {
outgoing.headers.host =
required(outgoing.port, options[forward || 'target'].protocol) && !hasPort(outgoing.host)
? outgoing.host + ':' + outgoing.port
: outgoing.host;
}
可以看到,这里只是修改了header中的host属性,并没有对origin进行任何处理。
思考两个问题
changeOrigin修改的是host,那么这个host的主要作用什么?
如果我们想修改origin,该怎么处理?
回答第一个问题,其实就是弄明白http协议中header中的host的作用。
其实在http-proxy-middleware的GitHub的readme中,有对changeOrigin的注释说明,从这段说明中就可以看出,修改host的作用是为了什么
options.changeOrigin: for virtual hosted sites
for virtual hosted sites也就是说为了虚拟主机而设置的。
那么虚拟主机是个什么东西呢?
举个例子:
有一个服务器,性能非常好,我想在这个机器上面部署了很多网站,但是这个机器对外的ip只有一个,要实现能访问这个机器上面的不同网站怎么办?
通过ip+端口?是一个办法,但是不太好,我们通常都是通过域名去访问一个网站,而且一般都不指定特定域名,而采用默认的80或者443端口。
那么我如何实现仅仅通过不同的域名就能访问到同一台机器的不同网站呢?那就是靠我们上面说的host来实现的。
当我们通过不同域名访问的时候,虽然通过域名解析都是指向同一台机器,但是这台机器收到请求后,就可以通过请求头中的host来判断本次请求是要访问哪个网站了,这就是host请求头的作用。
通过上面的解释,我们可以知道host请求头和跨域没有关系。
我们回到正题来,一般我们去设置changeOrigin字段,可能往往是想解决跨域的问题。
但是发现,设置了以后,么有生效,估计这才是你能看到这篇博客的原因。O(∩_∩)O哈哈~
那么我们沿着这个问题继续刨根问底。解决跨域,应该怎么处理?应该修改origin请求头。但是通过设置changeOrigin=true,修改的确实host请求头,而不是origin(这个名字起的确实让我们猝不及防,你就不能改成changeHost吗???)
那么我们怎修改origin请求头呢?很简单,去看createProxyMiddleware的函数就行了,到里面找找看,有没有提供给外面一个接口去修改请求值的地方。
看一下createProxyMiddleware函数的定义,我们得知里面是一个Options<TReq, TRes>
继续去看Options的定义,我们可以找有一个on的属性,需要提供一个OnProxyEvent对象
继续看这个对象,我们可以看到有一个proxyReq的属性,猜测这个应该就是提供给外面的接口,用于修改request的请求的地方。
那么我就通过实现proxyReq 方法来进修改request的header了,最后实现案例如下:
const proxyReq =(proxyReq, req, res, options) =>{
/// 在这里可以对原始的request 进行修改
proxyReq.removeHeader('origin');
console.log('proxyReq getHeaders', proxyReq.getHeaders());
}
app.use(createProxyMiddleware({
pathFilter:'/api/v1.0',
target: proxyUrl,
changeOrigin: true,//控制服务器接收到的请求头中host字段的值,注意不是origin的值!! 修改origin还得用onProxyReq事件
secure: false,
on: {
proxyReq: proxyReq
},
logger: console // 添加日志以便调试
})
);
总结一下
通过上面一步一步的分析来,让我们学到的不仅仅是这一个知识点,而是要学习一种分析解决问题的方法方式。授之于鱼,不如授之于渔。