msw通过service worker或node.js拦截器在网络层模拟axios请求响应,无需修改业务代码;需用绝对url匹配handler、保持baseurl一致,并在测试中启用server.listen。

Vue 项目中用 Axios 发起网络请求时,测试环境里直接调用真实接口会导致不稳定、不可控、难复现问题。MSW(Mock Service Worker)能真正“拦截”请求,在网络层模拟响应,不改业务代码,也不依赖真实后端。关键在于:Axios 请求照常发,MSW 在底层悄悄接管并返回预设数据。
MSW 拦截 Axios 请求的核心逻辑
MSW 并不修改 Axios 行为,而是通过浏览器的 Service Worker(前端)或 Node.js 的请求拦截器(测试环境)捕获所有 fetch 和 XMLHttpRequest 请求——而 Axios 底层正是基于这两者之一(浏览器中用 XMLHttpRequest,Vite/Vue3 默认构建下也兼容 fetch)。只要 Axios 发出的请求路径与 MSW handler 匹配,就会被拦截并返回模拟响应。
正确配置 MSW 测试环境(以 Vitest + Vue Test Utils 为例)
- 不 mock axios 实例本身(避免绕过真实请求流程),而是让 MSW 真实拦截 HTTP 调用
- 所有 handler 必须使用与生产环境完全一致的 URL 和 method(如
rest.post('https://api.example.com/login'))
npm install msw --save-dev
在 src/mocks/handlers.ts 中定义:
import { rest } from 'msw'
export const handlers = [
rest.post('https://api.example.com/login', (req, res, ctx) => {
const { username, password } = req.body as { username: string; password: string }
if (username === 'admin' && password === '123') {
return res(
ctx.status(200),
ctx.json({ token: 'mock-jwt-token', user: { id: 1, name: 'Admin' } })
)
}
return res(ctx.status(401), ctx.json({ message: 'Invalid credentials' }))
}),
]
在 vitest.setup.ts(或测试入口文件)中启用:
import { setupServer } from 'msw/node'
import { handlers } from './mocks/handlers'
const server = setupServer(...handlers)
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
afterEach(() => server.resetHandlers())
afterAll(() => server.close())
组件中正常使用 Axios(无需任何测试特供逻辑)
比如 LoginForm.vue:
<script setup>
import { ref } from 'vue'
import axios from '@/utils/request' // 你封装的 axios 实例
const loading = ref(false)
const login = async (data) => {
loading.value = true
try {
const res = await axios.post('/login', data) // 注意:这里用的是相对路径
console.log(res.data)
} catch (err) {
console.error(err.response?.data)
} finally {
loading.value = false
}
}
</script>
⚠️ 注意:若你封装的 axios 实例设置了 baseURL: 'https://api.example.com',那么 axios.post('/login') 实际发出的请求 URL 就是 https://api.example.com/login —— 这正是 MSW handler 中要匹配的完整地址。
针对不同 baseURL 场景的适配建议
- 如果开发/测试环境
baseURL是动态的(如import.meta.env.VUE_APP_API_BASE),MSW handler 必须用相同值,否则无法匹配 - 更稳妥做法:统一用绝对 URL 写 handler(如
rest.post('https://api.example.com/login', ...)),并在 axios 实例中固定baseURL,避免环境差异导致拦截失效
验证拦截是否生效的小技巧
- 在 handler 里加
console.log('MSW intercepted login request'),运行测试时看控制台是否有输出 - 故意写错 handler URL(如少一个
/),Vitest 会报Unhandled request错误 —— 这说明 MSW 已启动且在监听
不需要替换 axios、不需要 jest.mock('axios')、不需要在组件里判断环境。真实请求路径 + 真实请求方式 + 真实响应结构,测试才真正贴近线上行为。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











