changeOrigin 到底改了啥
前端开发中经常要配置接口代理服务,用来解决开发阶段的跨域问题。
无论是 webpack-dev-server 中的 proxy,还是 vite 中的 proxy,内部都是使用了同一个库 node-http-proxy。
一个代理的例子
在配置 proxy 时,通常是这样的:
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
server: {
// 配置代理服务
proxy: {
// 以 /api 开头的请求,全部转发到 target 设置的地址
'/api': {
target: 'https://demo.com',
changeOrigin: true
}
}
}
})
设置 target
目标的同时,有时还会配置一个 changeOrigin
属性。看名字,它好像用来改变 origin
请求头的值,将其改为 target
的值。
真的如此吗?
先看文档
- changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL
也就是说,changeOrigin 的默认值为 false,用来将 host 请求头修改为 target 的 URL。
🌰 通过一个例子演示
准备两个服务:
- 后端:使用 koa 创建的接口服务
- 前端:使用 @vue/cli 创建的 vue 项目
示例代码已上传到 Github 仓库。
Koa
在本地 3000 端口启动一个接口服务:
// server.js
const Koa = require("koa")
const body = require("koa-body")
const Router = require("@koa/router")
const app = new Koa()
const router = new Router()
app.use(body())
// post请求,携带 origin 头
router.post('/api/list', async ctx => {
console.log(ctx.headers)
ctx.body = {
code: 0,
msg: 'ok'
}
})
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
console.log(`服务器已启动: 3000`);
})
Vue
前端使用 axios
访问接口/api/list
:
// main.js
import axios from 'axios'
axios.post('/api/list').then(res => {
console.log(res)
})
设置 changeOrigin 为 false
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: false
}
}
}
此时的 origin
、host
头分别是:
Host: localhost:8080
Origin: http://localhost:8080
可以通过代理解决跨域问题:
服务端接收到的请求头信息是:
origin: 'http://localhost:8080'
host: 'localhost:8080'
设置 changeOrigin 为 true
devServer: {
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
}
浏览器端查看请求头信息:
Host: localhost:8080
Origin: http://localhost:8080
服务端接收到的请求头信息:
origin: 'http://localhost:8080'
host: 'localhost:3000'
发现
这一次,host 头的值变为 localhost:3000
,也就是 target 设置的接口服务器的地址了。
也就是,changeOrigin
这个配置项,修改的不是 origin
头,而是 host
头。
那么,修改 host 有什么特别的作用吗?
**答案是没有。**起码对于解决跨域问题没有。
换个角度看, changeOrigin
的默认值是 false
,也就是不改,说明不改的适用场景更广泛一些。
那如果改了 host
,能发挥出什么作用吗?
那就先看看 host
这个头本身的作用是什么。
host header
Host 请求头表示请求资源的网络主机和端口号, 比如我们访问上面的 localhost:8080 这个页面,那么它的 host 就是:
该请求头在 HTTP/1.1 版本中推出,是为了解决虚拟主机的问题。在 HTTP/1.0 中,一个域名绑定一个 IP 地址,一台服务器对应一个 IP,因此一台服务器只能运行一个站点。随着虚拟主机技术的发展,有时候需要在一台服务器上运行多个虚拟主机,此时服务器就可以通过 host 头来做不同的处理。
在运行 HTTP/1.1 协议的网站中,请求头中要求携带 host 头。现在很多网站都已经支持了 HTTP/2 版本协议,它就不要求携带 host 请求了。
看下百度:
看下主域名:
掘金已经全部采用 HTTP/2 了:
已经没有 host
请求头了:
小结
配置 changeOrigin
修改 host
,基本上没什么用。
🎀 关于 changeOrigin 的结论
通过上面的探究,基本可以得出以下结论:
- changeOrigin 配置项用来修改 host header,而非 origin header
- Host header 用来处理虚拟主机的问题,和跨域无关
- 一般情况下,设置代理时可以忽略这个配置项,保持默认即可
- 特殊情况下,很可能后端服务就用 host 做校验了,此时根据实际情况去设置
另一个问题:为什么浏览器网络面板观察不到 host 的修改?
因为浏览器运行的 js 代码,发出了一个网络请求,这个请求的 host 就是 localhost:8080
。
发出去之后,被本地的代理服务拦截到了,在这个地方将 host
修改了,再发往后端服务器。
也就是,host
修改时,浏览器已经将请求发出去了,所以观察不到。
🏁 最后
本文简单探讨了 changeOrigin
这个常见的配置项。用了这么多年,才发现一直“误会”了它。看来正应了那句老话:
纸上得来终觉浅,
绝知此事要躬行。