import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; import ts from "typescript"; async function loadClientHeaders() { const code = ts.transpileModule( await readFile(new URL("../src/lib/api/client-headers.ts", import.meta.url), "utf8"), { compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2022 } }, ).outputText; return import(`data:text/javascript;base64,${Buffer.from(code).toString("base64")}`); } const { buildBrowserApiHeaders, clientHeaders, clientIp } = await loadClientHeaders(); test("浏览器 X-User-Agent 带上 DevID 和 SysType", () => { const headers = buildBrowserApiHeaders("device-1"); assert.match(headers["X-User-Agent"], /DevID=device-1/); assert.match(headers["X-User-Agent"], /SysType=h5_/); assert.match(headers["X-User-Agent"], /BuildID=web/); assert.match(headers["X-User-Agent"], /system_name=Other/); }); test("服务端优先保留请求里的 X-User-Agent,并补 X-Real-IP", () => { const xua = "DevID=client;DevType=iPhone;SysType=h5_ios;Ver=1.0.0;BuildID=web;sid=abc"; const headers = clientHeaders( new Headers({ "User-Agent": " Mozilla/5.0 iPhone ", "X-User-Agent": xua, "X-Real-IP": "203.0.113.9", "X-Forwarded-For": "203.0.113.8, 10.0.0.1", }), ); assert.equal(headers["User-Agent"], "Mozilla/5.0 iPhone"); assert.equal(headers["X-User-Agent"], xua); assert.equal(headers["X-Real-IP"], "203.0.113.9"); assert.equal(headers["X-Forwarded-For"], undefined); }); test("没有 X-Real-IP 时取 X-Forwarded-For 第一段", () => { assert.equal(clientIp(new Headers({ "X-Forwarded-For": "198.51.100.4, 10.0.0.1" })), "198.51.100.4"); const headers = clientHeaders(new Headers({ "User-Agent": "Chrome", "X-Forwarded-For": "198.51.100.4, 10.0.0.1" })); assert.equal(headers["X-Real-IP"], "198.51.100.4"); assert.match(headers["X-User-Agent"], /SysType=h5_pc/); }); test("没有请求上下文时回退合成 X-User-Agent", () => { const headers = clientHeaders(undefined, { devID: "web-ssr" }); assert.equal(headers["User-Agent"], undefined); assert.match(headers["X-User-Agent"], /DevID=web-ssr/); assert.match(headers["X-User-Agent"], /system_name=Other/); }); test("服务端按 User-Agent 写入系统名称和系统版本", () => { const iphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1"; const ios = clientHeaders(new Headers({ "User-Agent": iphone, Cookie: "sid=abc" })); assert.match(ios["X-User-Agent"], /DevType=Apple iPhone mobile/); assert.match(ios["X-User-Agent"], /SysType=h5_ios/); assert.match(ios["X-User-Agent"], /BuildID=Safari 17\.2/); assert.match(ios["X-User-Agent"], /device_brand=Apple/); assert.match(ios["X-User-Agent"], /device_model=iPhone/); assert.match(ios["X-User-Agent"], /system_name=iOS/); assert.match(ios["X-User-Agent"], /system_version=17\.2/); assert.match(ios["X-User-Agent"], /sid=abc/); const android = "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"; const androidHeaders = clientHeaders(new Headers({ "User-Agent": android })); assert.match(androidHeaders["X-User-Agent"], /SysType=h5_android/); assert.match(androidHeaders["X-User-Agent"], /device_brand=Google/); assert.match(androidHeaders["X-User-Agent"], /device_model=Pixel 7/); assert.match(androidHeaders["X-User-Agent"], /system_name=Android/); assert.match(androidHeaders["X-User-Agent"], /system_version=13/); assert.match(androidHeaders["X-User-Agent"], /BuildID=Chrome 120\.0\.0\.0/); const windows = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; const pc = clientHeaders(new Headers({ "User-Agent": windows })); assert.match(pc["X-User-Agent"], /SysType=h5_pc/); assert.match(pc["X-User-Agent"], /system_name=Windows/); assert.match(pc["X-User-Agent"], /system_version=10\.0/); assert.match(pc["X-User-Agent"], /DevType=desktop/); });