axios 需要配多个 baseURL 怎么处理?用错场景反而更麻烦
先给结论:axios 里要对接多套后端,别在一个实例上反复改接口基地址,正确做法是按后端拆出多个 axios 实例,每个实例各自持有自己的接口基地址;只有临时切一次的场景才用请求拦截器动态改写。

新手最容易踩的坑是"改完再发":请求发出前把实例上的基地址改掉,结果并发请求互相覆盖,A 请求用上了 B 的地址,排查起来毫无规律。
本文给出三种写法并说明各自适合什么场景,重点讲清哪些情况不该动基地址。示例基于常见的请求库用法,版本差异会在边界一节说明。
先看结论
- 多套后端就拆多个实例:每个实例持有自己的接口基地址,互不干扰。
- 动态改写只适合少量例外:写进请求拦截器,用前缀判断走哪套后端。
- 别在请求前临时改接口基地址:实例是共享对象,并发场景下一定会互相覆盖。
一、最小场景:两套后端同时存在
把问题定死:页面要同时请求业务接口和文件服务,两个接口域名不一样,但都要带同一套鉴权头。两套后端意味着两个接口基地址,怎么放这两个值就是这里要解决的问题。
第一种写法是按后端拆 axios 实例:
import axios from 'axios';
const api = axios.create({ baseURL: 'https://api.example.com' });
const file = axios.create({ baseURL: 'https://file.example.com' });
api.interceptors.request.use((config) => {
config.headers.Authorization = localStorage.getItem('token');
return config;
});
export { api, file };
这段做的是建两个各自持有基地址的实例,鉴权只在业务实例上加。预期结果(未在本机执行):两个实例发出的请求分别指向各自的域名,互不影响。
第二种写法是不设基地址,在拦截器里按前缀决定:
const service = axios.create();
service.interceptors.request.use((config) => {
if (config.url.startsWith('/file')) {
config.baseURL = 'https://file.example.com';
} else {
config.baseURL = 'https://api.example.com';
}
return config;
});
这段做的是每次请求前按路径前缀挑一个基地址。它只在拦截器里改当次的配置对象,不会污染实例本身,这一点和直接改实例属性有本质区别。
请求相关的细节记不清时,AJAX 教程 里的示例可以直接对照。
二、什么场景该用哪种
接口基地址放在哪里,取决于两套后端要并存多久,按这个标准选基本不会错。
2.1 长期并存的两套后端用多实例
业务接口、文件服务、第三方开放接口,只要长期并存,就各自建一个实例。好处是基地址、超时、鉴权可以分别配置,出问题时定位也快。
2.2 少量例外用拦截器改写
只有个别接口走另一套后端时,为它单独建实例反而显得啰嗦。这时候用前缀判断,在拦截器里挑基地址更轻。
2.3 多环境切换交给环境变量
开发、测试、生产对应不同的域名,这类切换不要写死在代码里,交给环境变量在打包时决定。

三、用错场景反而更麻烦的地方
3.1 在请求前临时改实例属性
这是最典型的错误写法。接口基地址被临时改成另一个域名后,实例是共享对象,改它的属性会影响所有正在排队的请求,并发一上来就乱。
判断标准很直接:凡是出现"先改后发再改回来"的写法,都该换成多实例。
3.2 把域名写进每一个请求
把完整域名散落在各个请求定义里,换环境时要全局替换,漏一处就是线上事故。
3.3 忽略超时与重试的差异
不同后端的响应特征不一样,文件服务通常需要更长的超时。多实例的写法正好可以分别设置,这也是它优于统一改写的地方。
写法细节可以对照 JavaScript 教程 里的对象与函数章节确认。
3.4 模块导出的实例是单例
把实例集中在一个文件导出时,这个文件只会被加载一次,导出的实例在进程里是同一个对象。这本来是好事,但如果你图方便在实例上挂了"当前用户"之类的状态,并发请求就会互相读到对方的数据。实例只适合放配置和拦截器,请求级别的状态必须放在每次调用里。
四、验证清单
4.1 逐个域名称看网络面板
确认每个请求的地址前缀正确,尤其是并发触发的那几个。
4.2 鉴权头有没有带错
多实例时拦截器可能只挂在其中一个上,另一个实例的请求会缺少鉴权头。
4.3 换环境后重新打包验证
环境变量改完必须重启或重新打包,否则读到的还是旧值。
4.4 验证清单
- 检查:确认每个实例持有各自的接口基地址
- 运行:同时触发两个域名的请求,观察网络面板
- 预期:地址前缀各自正确,鉴权头按预期带上
- 失败:地址串到别的域名,说明有人在改实例属性
- 修复:把临时改属性的写法换成独立实例
- 验证:连续并发十次,结果始终一致才算通过

总结
多套后端并存的场景,按后端拆实例是最省心的一档;拦截器改写适合少量例外;环境差异交给环境变量。真正要避免的是在共享实例上临时改基地址。
三条要点带走:
- 接口基地址是实例级的配置,不要在一次请求里改来改去;
- 拦截器改的是当次配置对象,改实例属性则会污染所有排队请求;
- 域名不要散落在请求定义里,统一交给常量或环境变量。
下一步建议把实例集中在一个文件里导出,并给每个实例单独配置超时。属性细节可以对照 AJAX 速查手册 再核一遍。
常见问题
Q:能不能完全不设接口基地址?
A:可以,每个请求写完整地址。代价是换环境时要全局替换,域名一多就很难维护。
Q:并发请求为什么会串到别的域名?
A:因为改的是共享实例上的属性。改成按后端拆实例,或者在拦截器里改当次的配置对象。
Q:多个实例会不会增加体积?
A:几乎不会。实例本身只是配置对象,真正占体积的是请求库本身,只会被打包一次。
Q:环境切换用环境变量还是配置文件?
A:优先用环境变量,打包时按环境取值,一套代码可以对付多套后端,不需要为每个环境改代码。
Q:不同后端要不同的超时怎么办?
A:这正适合多实例。每个实例单独设置超时与重试,比在拦截器里判断更清晰。
延伸学习
想把这个知识点补扎实,可以按这个顺序来:
- 想把语言基础补系统,JavaScript 原生模块 可以跟一遍;
- 读一篇相关笔记 用 Ajax 请求服务器数据,看别人踩过的坑;
- 想随手验证一段代码,用 JavaScript 在线运行 跑一遍最快。