import { defineFakeRoute } from 'vite-plugin-fake-server/client'; // 简单的实体转义,避免在 XML 中出现非法字符;先替换 & 再替换其他符号,防止二次转义 function esc(s: string) { return s .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"') .replaceAll("'", '''); } // 从原始 XML 文本中提取某个标签的文本内容(弱解析,仅用于演示) function pickTag(xml: string, tag: string) { // 说明:使用非贪婪匹配并允许标签上带属性;N.B. 未处理命名空间与嵌套同名标签的复杂情形 const re = new RegExp(`<${tag}(?:\n|\r|\s|>|/)[^>]*>([\s\S]*?)<\/${tag}>`, 'i'); const m = xml.match(re); return m?.[1]?.trim() ?? ''; } // 通过 rawResponse 返回 XML 文本,便于在浏览器端演示 XML 解析 export default defineFakeRoute([ { method: 'GET', url: '/xml/sample', rawResponse(req, res) { // 通过查询参数自定义返回的 XML 字段 // 支持的参数:to, from, heading, body, id, createdAt const url = new URL(req.url!, 'http://localhost'); const q = url.searchParams; const to = q.get('to') ?? 'George'; const from = q.get('from') ?? 'John'; const heading = q.get('heading') ?? 'Reminder'; const body = q.get('body') ?? "Don't forget the meeting at 3 PM today."; const id = q.get('id') ?? '42'; const createdAt = q.get('createdAt') ?? '2025-09-02T10:00:00Z'; const xml = ` ${esc(to)} ${esc(from)} ${esc(heading)} ${esc(body)} ${esc(id)} ${esc(createdAt)} `; res.writeHead(200, { 'Content-Type': 'application/xml; charset=UTF-8' }); res.end(xml); }, }, { method: 'POST', url: '/xml/submit', rawResponse(req, res) { const chunks: Buffer[] = []; req.on('data', (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk))); req.on('end', () => { const contentType = String(req.headers['content-type'] || '').toLowerCase(); const raw = Buffer.concat(chunks).toString('utf8'); // 默认值,与 GET 一致 let to = 'George'; let from = 'John'; let heading = 'Reminder'; let body = "Don't forget the meeting at 3 PM today."; let id = '42'; let createdAt = new Date().toISOString(); try { if (contentType.includes('application/json')) { const data = JSON.parse(raw || '{}'); to = data.to ?? to; from = data.from ?? from; heading = data.heading ?? heading; body = data.body ?? body; id = data.id ?? id; createdAt = data.createdAt ?? createdAt; } else if (contentType.includes('application/xml') || contentType.includes('text/xml')) { // 解析 XML 请求体中常用字段(演示用,未处理命名空间/CDATA 等复杂场景) to = pickTag(raw, 'to') || to; from = pickTag(raw, 'from') || from; heading = pickTag(raw, 'heading') || heading; body = pickTag(raw, 'body') || body; id = pickTag(raw, 'id') || id; createdAt = pickTag(raw, 'createdAt') || createdAt; } else if (contentType.includes('application/x-www-form-urlencoded')) { // 简单解析表单:key=value&…;此处演示用途,未处理复杂编码场景 const params = new URLSearchParams(raw); to = params.get('to') ?? to; from = params.get('from') ?? from; heading = params.get('heading') ?? heading; body = params.get('body') ?? body; id = params.get('id') ?? id; createdAt = params.get('createdAt') ?? createdAt; } } catch { // 忽略解析错误,保持默认值 } const xml = ` ${esc(to)} ${esc(from)} ${esc(heading)} ${esc(body)} ${esc(id)} ${esc(createdAt)} `; res.writeHead(200, { 'Content-Type': 'application/xml; charset=UTF-8' }); res.end(xml); }); }, }, ]);