Files
portal-mini-front/mock/plugin.ts
T
2026-10-27 23:26:21 +08:00

57 lines
2.0 KiB
TypeScript

import type { Plugin } from 'vite'
import { mockRules, type MockContext } from './index'
const MOCK_PREFIX = '/api/v1'
function readBody(req: NodeJS.ReadableStream): Promise<string> {
return new Promise((resolve) => {
let raw = ''
req.on('data', (chunk) => (raw += chunk))
req.on('end', () => resolve(raw))
})
}
/**
* 本地 mock 中间件:始终挂载于 dev,但仅命中「全局 mock 开启」或标记 alwaysMock 的规则。
* 这样新增页面的接口可被单独 mock,而项目其余接口仍走真实后端代理。
* 不引入三方 mock 依赖,避免污染生产依赖树。
*/
export function mockPlugin(globalMock = false): Plugin {
return {
name: 'portal-mock',
apply: 'serve',
configureServer(server) {
server.middlewares.use((req, res, next) => {
if (!req.url?.startsWith(MOCK_PREFIX)) return next()
const requestUrl = new URL(req.url, 'http://localhost')
void (async () => {
const raw = req.method === 'GET' ? '' : await readBody(req)
const isJsonBody = (req.headers['content-type'] ?? '').includes('application/json')
const rule = mockRules.find(
(item) =>
item.method === (req.method ?? 'GET').toUpperCase() &&
item.pattern.test(requestUrl.pathname) &&
(globalMock || item.alwaysMock === true),
)
if (!rule) return next()
const matched = requestUrl.pathname.match(rule.pattern)
const ctx: MockContext = {
url: requestUrl.pathname,
params: matched ? matched.slice(1) : [],
query: Object.fromEntries(requestUrl.searchParams.entries()),
body: raw && isJsonBody ? JSON.parse(raw) : {},
}
res.setHeader('Content-Type', 'application/json;charset=utf-8')
res.end(
JSON.stringify({ code: '00000', data: rule.handler(ctx) ?? null, msg: 'success' }),
)
})()
})
},
}
}