# @cedvict/http-guardian 中文文档

规范地址：https://npmcn.com/package/%40cedvict/http-guardian/

版本：0\.5\.0
npm 元数据更新时间：2026-10-22T16:47:35.504Z
中文译文更新时间：2026-11-09T08:38:03.832Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40cedvict/http-guardian
原文对照：https://npmcn.com/package/%40cedvict/http-guardian/?lang=original
项目主页：https://hguardian.uman.social/
源码仓库：https://gitlab.com/code-idea/code-libs/npm/http-guardian

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：602 kB，83 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- Node.js 要求：\>=22
- 运行依赖：0 个
- 首次发布：2026-02-08T19:07:06.947Z
- 最新版本发布：2026-10-22T16:47:35.299Z
- 近 30 天下载量：3468（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：22（近 12 个月 22 个）

## 中文简介

TypeScript 的配置 HTTP 客户端: auth (career/cookie), 守护,缓存+dedupe, 动态信封解析预设, 通知, 重定向处理 .

## 安装

```sh
npm install @cedvict/http-guardian
```

也可以使用：`pnpm add @cedvict/http-guardian`、`yarn add @cedvict/http-guardian`、`bun add @cedvict/http-guardian`

## README

# @cedvict/http-guardian (中文(简体) )

HTTP 核心客户端( 承诺) `fetch`。 。 。 .

## 安装

**运行时间要求 :** 节点 **第22页** (或任何现代浏览器/更新运行时间) `fetch`) (中文(简体) ).

如果你在一个没有全局的环境运行 `fetch`,明确通过 `createHttpClient({ fetch })`。 。 。 .

释放(`0.0.1-next.*`发表于 `next` dis. 直至a 稳定版本已出炉, `latest` 指向更旧的预放:从 `next`,或者将准确的版本标出.

```bash
npm i @cedvict/http-guardian@next
```

## 快例( REST 经典信封)

```ts
import { createHttpClient, bearerAuth, createApiParserRestClassic, memoryCache } from "@cedvict/http-guardian";

const api = createHttpClient({
  baseUrl: "https://api.example.com",
  auth: bearerAuth(() => localStorage.getItem("token")),
  parser: createApiParserRestClassic(),
  cache: memoryCache({ maxEntries: 500 })
});

const res = await api.get<{ id: string; name: string }>("/me", {
  cache: { ttlMs: 30_000, tags: ["me"] }
});

if (res.ok) console.log(res.data.name);
else console.error(res.errors);
```

## 二进制回复

使用明确的响应类型进行下载. 成功响应绕过 JSON信封解析器 他们的字节保持不变 错误响应仍然使用 普通内容类型解码器,它保存结构化的 API 错误.

```ts
const report = await api.get<Blob>("/reports/monthly", {
  responseType: "blob",
  headers: { accept: "application/pdf" },
});

if (report.ok) {
  const url = URL.createObjectURL(report.data);
  // Open or download the URL, then call URL.revokeObjectURL(url).
} else {
  console.error(report.errors);
}
```

`responseType: "arrayBuffer"` 还可用于以字节为导向的处理. 二进制请求未收到默认 `Accept: application/json` 标题, 并保存缓存/调用密钥 `blob` 财务报告和审定财务报表 `arrayBuffer` 答复分开.

## 预设

-   `createApiParserRestClassic()`
-   `createApiParserLaravel()`
-   `createApiParserNest()`
-   `createApiParserGraphQL({ allowPartialData? })`
-   `createApiParserStructured({ exposeMeta?, honorRetryableHint? })` - 解析器 帮助打字: `{ success, code, message, details, retryable, issues[], i18n, meta }`。 。 。 . {\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}那又怎样 `AppError` 端口 `code`, (中文(简体) ), `message` 和布伦打字 `retryable`后台和冠军`category`, (中文(简体) ), `severity`, (中文(简体) ), `i18n`, (中文(简体) ), `traceId`, (中文(简体) ), `spanId`, (中文(简体) ), `envelope`) 不安不负责任 `details`. 发布 peut 重置器 `retryable` (原始内容存档于2017-09-21). de l'enveloppe.
-   `createApiParserProblem({ codeMembers?, requestIdHeader? })` - 问题细节 (RFC 9457, `application/problem+json`) (中文(简体) ). 来自 `detail`,则 `title`· ; `code` 从第一个非空白成员 `codeMembers` (默认) `["code"]`, (中文(简体) ), 譬如说. `["rule", "code"]`);每个扩展保存在 `details.extensions` (单位:千美元)`ProblemErrorDetails`),与 `retryAfter` (单位:千美元) `Retry-After` 标题)和 `requestId`布尔 `retryable` 成员变成 `AppError.retryable`。 。 。 . 验证问题给出一个 `AppError` 每个输入,从 `errors` (单位:千美元)`{ detail, pointer }`)或(或) `invalid-params` (单位:千美元)`{ name, reason }`) (中文(简体) ).
-   `createApiParserDetail({ requestIdHeader? })` ——API不成功 信封:成功体是数据,错误是 `{ detail, code?, retryAfter?, requestId? }`。 。 。 . 字符串 `detail` 给一个 `AppError` (单位:千美元)`code` 保留);422项验证 `detail` 数组给出一个 `AppError` 每个输入 `field` (单位:千美元)`loc` 无 联合国 `body`编号 :`query`/...来源)和 `code` (议题) `type`) (中文(简体) ). `details` (单位:千美元)`DetailErrorDetails`载体 `retryAfter` (单位:千美元) `Retry-After` 标题, 延迟或 HTTP 日期,否则身体字段,以整秒计), `requestId` (躯体,其他) `X-Request-ID`, (中文(简体) ), `loc` 和生的 `body`。 。 。 .

解析器可以读取一个失败的响应的页眉 : `getErrors(raw, status, response?)` 接收 `{ headers }` 作为可选的第三个论据.

没有 `notifier`,客户端使用 `consoleNotifier`,它每写 失败到控制台。 过 `silentNotifier` 当应用程序显示时 自有信件来源 `result.errors`。 。 。 .

## Auth 模式

-   `bearerAuth(() => token)`
-   `cookieAuth({ credentials: "include", csrf: { headerName, getToken } })`
-   `noAuth()`

## 警卫

守卫在无中相器械中.

### `bearerRefreshGuard({ refreshFn, onAuthFailed?, ... })`

刷新 JWT 显示器 **单机** : sur 401, 无人知晓 `refreshFn()` 时间轴:; {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}401 reçues pendant sce sreaking sententent dans une 队列 存档副本 (原始内容存档于2013-10-10). Partagée puis sont rejouées avec le nouveau sord. 刷新音乐, `onAuthFailed(error)` 排队时的法语和法语 (原始内容存档于2017-10-21) (英语). vorient le 401 d'grounde.

```ts
import { createHttpClient, bearerAuth, bearerRefreshGuard } from "@cedvict/http-guardian";

createHttpClient({
  auth: bearerAuth(() => tokenStore.access()),
  guards: [
    bearerRefreshGuard({
      refreshFn: async () => {
        const { accessToken, refreshToken } = await api.refresh();
        tokenStore.set(accessToken, refreshToken);
        return { accessToken, refreshToken };
      },
      onAuthFailed: () => router.navigate("/login"),
      skipRefreshFor: (ctx) => ctx.url.includes("/auth/"),
    }),
  ],
});
```

### `csrfGuard({ tokenFromCookie?, tokenFromStorage?, tokenFromHeader?, headerName?, applyTo? })`

弹出去头 `X-CSRF-Token` (défaut) 变种动物 (单位:千美元)`POST`编号 :`PUT`编号 :`PATCH`编号 :`DELETE`) (中文(简体) ). **安保部门安全** 页:1 `tokenFromCookie` 使用率最高 浏览器( r)`typeof document === 'undefined'`),le guard shippe silencieusement. (原始内容存档于2018-09-31).

```ts
csrfGuard(
  isPlatformBrowser(platformId)
    ? { tokenFromCookie: "csrf_token" }
    : { tokenFromStorage: () => null },
);
```

### `correlationIdGuard({ headerName?, generator?, readResponseHeader? })`

弹出去头 `X-Correlation-Id` (UUID v4 par défaut,倒计时) `Math.random()`+时间戳 si `crypto.randomUUID` 页:1 (原始内容存档于2018-09-21) (英语). L'ID est **稳定 请求重试** (法语). (原始内容存档于2018-09-26) (英语). Si la réponse contient le même header, 仅此而已 `ctx.meta.correlationId` 下游插件倾斜 (伐木工,哨兵,奥特尔).

> 💡 **模式“ X- request-Id ”** : si ton后端(ops, ELK, Datadog...) 使用 le 页眉 `X-Request-Id` plut-t que (英语) `X-Correlation-Id` 倒接缝线 日志前/后端, 更改正则 `headerName` 数字 :
> 
> ```ts
> correlationIdGuard({ headerName: "X-Request-Id" })
> ```
> 
> (原始内容存档于2018-10-21) (英语). Pas besoin d'OpenTelemetery côté front, ni d'un 二等后卫: C'est le même (原始内容存档于2012-10-12). Mécanisme avec un nom différent. 可组合的avec un OTel `traceparent` 数字 : {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}什么? {\\fn黑体\\fs22\\bord1\\shad0\\3ahbe\\4ah00\\fscx67\\fscy66\\2chffffff\\3ch808080}什么.

### `idempotencyGuard({ headerName?, applyTo?, respectExisting? })`

弹出去头 `X-Idempotency-Key` (乌伊德·德福特) `POST`编号 :`PUT`编号 :`PATCH`。 。 。 . 拉克莱斯特 **稳定企业重试** ——活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活. 尊重 une Clé 四分卫通过 `RequestOptions.idempotencyKey`, (中文(简体) ), `ctx.idempotencyKey`,通过头来指导.

## 食谱:映射器 le `traceId` 后端 QQ 哨兵/ OTel 前端

Quand le 后端 renvoie une enveloppe avec un 页面存档备份,存于互联网档案馆 `meta.traceId` 页:1 `spanId`(中文(简体) ) - 通过类型 `createApiParserStructured` 缝纫机用具 追踪空地/活动前端的克恩事件 vers la trace后端对应(et 反向).

{\\fn黑体\\fs22\\bord1\\shad0\\3aHBE\\4aH00\\fscx67\\fscy66\\2cHFFFFFF\\3cH808080}蓝色的胸口

1.  **`correlationIdGuard`** 格内尔·恩 `X-Correlation-Id` 支持恢复, 和lit le header de réponse pour exploser l'ID dans 相接(英文) `ctx.meta.correlationId`。 。 。 .
2.  **`createApiParserStructured`** 储存 `traceId` 编号 : `spanId` 达斯 `errors[].details` (en cas d'erreur) (法语). 圣克萨斯圣克萨斯圣克萨斯 通过无宠卫士 dédié.

```ts
import {
  createHttpClient,
  bearerAuth,
  correlationIdGuard,
  createApiParserStructured,
  type Guard,
} from "@cedvict/http-guardian";
import { sentryPlugin } from "@cedvict/http-guardian-plugin-sentry";
import { otelPlugin } from "@cedvict/http-guardian-plugin-otel";
import * as Sentry from "@sentry/browser";

// Lit X-Trace-Id / X-Span-Id de la réponse et les pose sur ctx.meta pour
// les plugins downstream (sentry, otel, logger).
const traceMetaGuard: Guard = async (ctx, next) => {
  const res = await next(ctx);
  const traceId = res.headers.get("x-trace-id");
  const spanId = res.headers.get("x-span-id");
  if (traceId || spanId) {
    ctx.meta ??= {};
    if (traceId) ctx.meta.traceId = traceId;
    if (spanId) ctx.meta.spanId = spanId;
  }
  return res;
};

const api = createHttpClient({
  baseUrl: "https://api.example.com",
  auth: bearerAuth(() => token),
  parser: createApiParserStructured(),
  guards: [correlationIdGuard(), traceMetaGuard],
  plugins: [
    sentryPlugin({
      // shouldCapture reçoit le ctx → on lit ctx.meta pour tagger l'event Sentry.
      shouldCapture: ({ status, ctx }) => {
        if (status && status >= 500) {
          Sentry.getCurrentScope().setTags({
            "backend.trace_id": ctx.meta?.traceId ?? "",
            correlation_id: ctx.meta?.correlationId ?? "",
          });
          return true;
        }
        return false;
      },
    }),
    otelPlugin({
      setAttributes: (span, ctx) => {
        if (ctx.meta?.traceId) span.setAttribute("backend.trace_id", ctx.meta.traceId);
        if (ctx.meta?.spanId) span.setAttribute("backend.span_id", ctx.meta.spanId);
        if (ctx.meta?.correlationId) span.setAttribute("correlation_id", ctx.meta.correlationId);
      },
    }),
  ],
});
```

科特错失,我被贬 `createApiParserStructured` 揭发déjà `traceId` 编号 : `spanId` 达斯 `result.errors[0].details` 数字 :

```ts
const r = await api.post("/orders", { json: payload });
if (!r.ok) {
  const d = r.errors[0]?.details as { traceId?: string; spanId?: string } | undefined;
  console.error("backend trace:", d?.traceId, d?.spanId);
}
```

## 重定向

-   `redirects: { mode: "follow" | "manual" | "error", maxHops, onRedirect }`

## 测试

见 `TESTING.md`。 。 。 .

## Cookie 会话刷新后卫(单飞、冷却、反跳动)

如果您使用基于 cookie 的 auuth , 而您的后端会显示一个更新的端点, 您可以添加安全更新的 guard :

```ts
import { createHttpClient, cookieAuth, cookieSafeRefreshGuard, createApiParserRestClassic } from "@cedvict/http-guardian";

const api = createHttpClient({
  baseUrl: "https://api.example.com",
  auth: cookieAuth({ credentials: "include" }),
  parser: createApiParserRestClassic(),
  guards: [
    cookieSafeRefreshGuard({
      refreshPath: "/auth/refresh", // or absolute: "https://auth.example.com/refresh"
      maxRetry: 1,                  // anti-loop (default)
      honorRetryAfter: true         // cooldown on 429 (default)
    })
  ],
});
```

您可以按请求禁用任何认证/ 新鲜行为 `noAuth: true`数字 :

```ts
await api.get("/public/health", { noAuth: true });
```

## 通知编辑( 可选)

如果您提供了自定义通知符并记录/发送事件到遥测,您可以添加一个 `redact` 函数 从事件有效载荷中去除秘密(例如: `url`:

```ts
import type { Notifier, NotifyEvent } from "@cedvict/http-guardian";

const notifier: Notifier = {
  redact: (e: NotifyEvent) => ({ ...e, url: e.url.replace(/\?.*$/, "") }),
  notify: (e) => console.error(e),
};
```

## 预设构建器和别名( sable DX)

如果您想要一个1行设置而不失去访问权限 `createHttpClient`,使用预设构建器 :

```ts
import { createPresetBuilder } from "@cedvict/http-guardian";

const api = createPresetBuilder({ baseUrl: "https://api.example.com" })
  .cookie({ credentials: "include" })
  // opt-in only:
  // .cookieRefresh({ refreshPath: "/auth/refresh", mePath: "/auth/me" })
  .create();
```

异名( 围绕预设构建器的薄膜):

-   `createCookieClient({ baseUrl, refresh?: CookieSafeRefreshGuardOptions | null, ... })`
-   `createBearerClient({ baseUrl, getToken, ... })`

### 稳定认证刷新策略

-   **Cookie 认证**: 刷新为 **选入** (编) `cookieRefresh(...)` 或通过 `refresh` 改为 `createCookieClient`) (中文(简体) ).
-   **持有者认证**: 刷新为 **默认禁用**。 。 。 .

## 插件( 配置时间)

`plugins` 被同步应用于 `createHttpClient(...)` 以更改选项草案对象.

合同:

-   应用 **顺序**
-   由 `name` (第一胜负)

## 常见问题

### @cedvict/http-guardian 是什么？

TypeScript 的配置 HTTP 客户端: auth \(career/cookie\), 守护,缓存\+dedupe, 动态信封解析预设, 通知, 重定向处理 \.

### 如何安装 @cedvict/http-guardian？

在项目目录运行 npm install @cedvict/http-guardian，或使用 pnpm add / yarn add / bun add。

### @cedvict/http-guardian 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @cedvict/http-guardian 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @cedvict/http-guardian 需要什么版本的 Node\.js？

package\.json 的 engines 字段要求 Node\.js \>=22。版本不符时 npm 默认只给出警告，开启 engine-strict 后会拒绝安装。

### @cedvict/http-guardian 可以商用吗？

@cedvict/http-guardian 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @cedvict/http-guardian 的下载量有多少？

根据 npm 官方下载统计，@cedvict/http-guardian 在 2026/10/10 – 2026/11/08 这 30 天内被下载 3,468 次，日均约 116 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @cedvict/http-guardian 还在维护吗？

最新版本 0\.5\.0 发布于 2026/10/23（17 天前）；至今共发布 22 个版本，其中过去 12 个月发布了 22 个；首次发布于 2026/02/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

