feat: W3C traceparent 极简透传——网关补发、信封续链(观测尽力而为)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
lovefyf
2026-08-13 12:23:30 +08:00
co-authored by Claude Opus 4.8
parent e9fc35e605
commit 0b83cb5fb4
2 changed files with 17 additions and 0 deletions
+4
View File
@@ -1,4 +1,5 @@
import type { Context } from 'hono';
import { newTraceparent } from '../../shared/trace';
const STRIP_HEADERS = ['x-user-id', 'x-user-roles', 'x-internal-token', 'host', 'content-length'];
@@ -21,6 +22,9 @@ export async function forward(c: Context, target: string, stripPrefix: string):
url.search = new URL(c.req.url).search;
const headers = new Headers(c.req.raw.headers);
for (const h of STRIP_HEADERS) headers.delete(h);
// 网关是外部请求的第一跳:调用方没带 traceparent 就在这里补发一条,让下游一路 childOf 续链。
// 已有的绝不覆盖——那会把上游(浏览器/上级网关)已经开好的链从中间截断。
if (!headers.has('traceparent')) headers.set('traceparent', newTraceparent());
const method = c.req.method;
const init: RequestInit & { duplex?: 'half' } = { method, headers };
if (method !== 'GET' && method !== 'HEAD') {
+13
View File
@@ -0,0 +1,13 @@
import { randomBytes } from 'node:crypto';
const SHAPE = /^00-([0-9a-f]{32})-[0-9a-f]{16}-[0-9a-f]{2}$/;
export function newTraceparent(): string {
return `00-${randomBytes(16).toString('hex')}-${randomBytes(8).toString('hex')}-01`;
}
export function childOf(parent?: string): string {
const m = parent ? SHAPE.exec(parent) : null;
if (!m) return newTraceparent();
return `00-${m[1]}-${randomBytes(8).toString('hex')}-01`;
}