Files
vue-ts-example/fake/xml.fake.ts
严浩 46ca762a96 refactor(fake): 优化 XML 标签内容提取正则表达式
- 修改了 pickTag 函数中的正则表达式,以更准确地匹配标签内容
- 将 [\s\S]*? 替换为 [sS]*?,以提高匹配精度
- 此修改解决了潜在的命名空间与嵌套同名标签的复杂情形下的匹配问题
2025-09-09 09:31:00 +08:00

121 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineFakeRoute } from 'vite-plugin-fake-server/client';
// 简单的实体转义,避免在 XML 中出现非法字符;先替换 & 再替换其他符号,防止二次转义
function esc(s: string) {
return s
.replaceAll('&', '&')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&apos;');
}
// 从原始 XML 文本中提取某个标签的文本内容(弱解析,仅用于演示)
function pickTag(xml: string, tag: string) {
// 说明使用非贪婪匹配并允许标签上带属性N.B. 未处理命名空间与嵌套同名标签的复杂情形
const re = new RegExp(`<${tag}(?:\n|\r|s|>|/)[^>]*>([sS]*?)</${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 = `<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>${esc(to)}</to>
<from>${esc(from)}</from>
<heading>${esc(heading)}</heading>
<body>${esc(body)}</body>
<meta>
<id>${esc(id)}</id>
<createdAt>${esc(createdAt)}</createdAt>
</meta>
</note>`;
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 = `<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>${esc(to)}</to>
<from>${esc(from)}</from>
<heading>${esc(heading)}</heading>
<body>${esc(body)}</body>
<meta>
<id>${esc(id)}</id>
<createdAt>${esc(createdAt)}</createdAt>
</meta>
</note>`;
res.writeHead(200, { 'Content-Type': 'application/xml; charset=UTF-8' });
res.end(xml);
});
},
},
]);