# @codefusion-cc/workers-http 中文文档

规范地址：https://npmcn.com/package/%40codefusion-cc/workers-http/

版本：0\.1\.4
npm 元数据更新时间：2026-10-26T13:14:21.250Z
中文译文更新时间：2026-11-10T08:17:42.166Z
软件包许可：MIT

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

原始 npm 页面：https://www.npmjs.com/package/%40codefusion-cc/workers-http
原文对照：https://npmcn.com/package/%40codefusion-cc/workers-http/?lang=original
项目主页：https://github.com/codefusion-cc/codefusion#readme
源码仓库：https://github.com/codefusion-cc/codefusion

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

- 包体积（解压后）：88.6 kB，28 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- Node.js 要求：\>=20
- 运行依赖：1 个
- 首次发布：2026-10-01T19:21:49.895Z
- 最新版本发布：2026-10-26T13:14:20.900Z
- 近 30 天下载量：2141（2026-10-10 至 2026-11-08，npm 官方下载统计）
- 已发布版本数：8（近 12 个月 8 个）

## 中文简介

Cloudflare Worker的API的HTTP管道: 错误被抛出作为答案, API的路线, JSON 的响应, 绑定了 JSON 和身体读取, 客户端的地址和网络, 同源检查, 费率限制 a RatLimit 绑定, cookie, SHA-256 和 a s

## 安装

```sh
npm install @codefusion-cc/workers-http
```

也可以使用：`pnpm add @codefusion-cc/workers-http`、`yarn add @codefusion-cc/workers-http`、`bun add @codefusion-cc/workers-http`

## README

# @ codumation-cc/ works- http (中文(简体) )

一个Cloudflare工人API的HTTP管道:抛出错误作为答案,一个API的路线,JSON的响应,JSON和身体读取 有限制的,客户的地址和网络,同源的cookie通话检查,对工人的费率限制 RaseLimit绑定,JSON的答案保存在工人的缓存, cookie, SHA-256, 以及一个单页的应用程序的页面 访问者写了地址 它运行在工人 和任何运行时间 `Request`,流和WebCrypto(20+节点) 一个依赖是 `@codefusion-cc/workers-crypto`。 。 。 .

```sh
npm install @codefusion-cc/workers-http
```

## 一个地方回答错误

手摇 `HttpError` 任何不是幸福的答案, 也一样 `readJson`, (中文(简体) ), `readBody`, (中文(简体) ), `requireSameOrigin`, (中文(简体) ), `rateLimit`页:1 `Router`是因为 `route` 财务报告和审定财务报表 `serveSinglePageApp`工人将任何被扔到一个地方的反应:

```ts
import { clientNetwork, errorResponse, HttpError, json, rateLimit, readJson, requireSameOrigin } from '@codefusion-cc/workers-http'

export default {
  async fetch(request, env) {
    try {
      return await route(request, env)
    } catch (error) {
      return errorResponse(error, { request }) // HttpError: its status and body; anything else: a 500 that reveals nothing, logged
    }
  },
} satisfies ExportedHandler<Env>

async function signIn(request: Request, env: Env) {
  requireSameOrigin(request, [env.DEV_ORIGIN])                     // 403 for a page on another site
  await rateLimit(env.AUTH_LIMITER, clientNetwork(request))        // 429 with retry-after
  const { email } = await readJson<{ email?: unknown }>(request)   // 415, 413, 400
  if (typeof email !== 'string') throw new HttpError(422, 'Enter your e-mail', { fieldErrors: { email: 'Required' } })
  return json({ ok: true })
}
```

一个 `HttpError` 答题 `{ error, code?, fieldErrors?, ...data }` 及其地位和 `headers`它的地位必须是: 400至599(其他任何东西都投出RangeError). `errorResponse` 还回答另一个安装的复制件所作的一个 包( 哪个) `instanceof` 因此,在另一个软件包中抛出的错误仍然得到其状态.

鉴于 `request`, (中文(简体) ), `errorResponse` 也取消了一个没有读到的身体, 所以一个上传在读之前被拒绝了 (a 401 on a PUT) 即刻停止,而不会跑到它的尽头.

`json(data, init)` 发送 `application/json; charset=utf-8` 财务报告和审定财务报表 `cache-control: no-store` 除非 `init` 套装 他们. `init.headers` 可能是一个 `Headers` 数个 `set-cookie`。 。 。 . `jsonError(status, message)` 是同一个身体 作为被丢弃的HtpError, 为返回而不是扔.

### 应用语言

包裹信息为英语. `errorResponse` 用代码交换应用程序的措辞,留下任何 信件, 应用程序单独写( e)`readBody`是因为 `message`,它自己的 Http 错误 :

```ts
errorResponse(error, {
  messages: {
    unsupported_media_type: 'Wyślij dane jako JSON.',
    body_too_large: 'Za duże zapytanie.',
    length_required: 'Wyślij zapytanie z nagłówkiem Content-Length.',
    unreadable_body: 'Nie udało się odczytać zapytania.',
    invalid_json: 'Nieprawidłowe dane.',
    cross_origin: 'Odrzucono zapytanie z innej strony.',
    rate_limited: 'Zbyt wiele prób. Odczekaj minutę i spróbuj ponownie.',
    not_found: 'Nie znaleziono.',
    method_not_allowed: 'Ten adres nie przyjmuje takiego zapytania.',
    server_error: 'Wystąpił błąd serwera. Spróbuj ponownie.',
  },
  onError: error => console.error('unhandled', error), // console.error by default; a throwing logger cannot break the answer
})
```

## 路线

`Router` 保留 API 的路径, 方法和路径 任何应用程序称为处理器 用于:

```ts
import { errorResponse, json, Router } from '@codefusion-cc/workers-http'

type Handler = (request: Request, env: Env, params: Record<string, string>) => Response | Promise<Response>

const api = new Router<Handler>()
  .on('GET', '/api/orders/new', () => json({ draft: true }))       // before the parameter that would take "new"
  .on('GET', '/api/orders/:id', (_request, _env, { id }) => json({ id }))
  .on('DELETE', '/api/orders/:id', removeOrder)

export default {
  async fetch(request, env) {
    try {
      const { handler, params } = api.route(request.method, new URL(request.url).pathname)  // 404, 405
      return await handler(request, env, params)
    } catch (error) {
      return errorResponse(error)
    }
  },
} satisfies ExportedHandler<Env>
```

-   A 类 `:name` 段是一个参数: 它需要一个非空段, 它的值会到达 已解码的% (%)`Bosch%20%2B` 实值 `Bosch +`; 其编码被破损者将保持发送状态,解码值可以 拿着 `/`) (中文(简体) ). 所有其它部分都碰巧碰面 信箱和后面的斜线 以及ASCII以外的文本 写得很清楚: `/api/zamówienia` 满足浏览器的 `/api/zam%C3%B3wienia`。 。 。 .
-   在对固定文本进行比较之前,不读取请求中的脱逃: `/api/%61dmin/users` 没有 `/api/admin/users` (该词 是一个404,或者一个参数的值。 因此,一个检查应用程序 在路径之前的路径,例如 `pathname.startsWith('/api/admin/')`,而且路由器总是同意一个请求的路径。 参数 值被解码,所以 `/api/:area/users` 获得 `admin` 从 `%61dmin`: 处理器从不为 路径.
-   第一条路线增加了符合答案的路线. 一个方法被满足了,但是 `HEAD`: 一个路径的 `GET` 路由应答 当路径没有时 `HEAD` 它自己的路线,运行时间发送 答案没有它的躯体.
-   `route(method, pathname)` 掷出404枚 `not_found` 对于一条没有路径,和 405 `method_not_allowed` 与 `allow` (路径确实回答的方法) 对于一个只有其他方法的路径. `match` 返回为无效 对于两者, 对于一个应用 答案自己.
-   `on` 为编程错误扔出 TypeError : 一个不是大写字母的方法, 一个不是一个路径 (无领导) `/`页:1 `?`页:1 `#`页:1 `..`页:1 `:` 部分不是 `:name`,在一个路径中两次参数,和一个 第二条路由 对于一个方法 和路径有一个, 它永远无法回答.

## 阅读机构

| 打电话 | 拒绝 |
| --- | --- |
| `readJson(request, options)` | 第415条 `unsupported_media_type`: 内容类型不 `application/json` 或者说 `application/*+json`. 413 (中文(简体) ) `body_too_large`. 400 (中文(简体) ) `unreadable_body`. 400 (中文(简体) ) `invalid_json`:没有身体,没有UTF-8,没有JSON,或者没有物体. |
| `readBody(request, options)` | 413号 `body_too_large`、400个 `unreadable_body` (上传中断). 解析字节;无正文为空字节. 也需要一个答复,例如从另一个服务处得到的. |
| `streamBody(request, { maxBytes }, store)` | 411号 `length_required`:无Content-Length,或非整数. 413号 `body_too_large`. 400 (中文(简体) ) `unreadable_body`: 或多或少比所申报的字节. 电话 `store(body, size)` 身体是一条溪流 `size` 字节,用于一个需要一串已知长度的流的商店,解决它所解决的问题. |

-   `maxBytes` (默认) `MAX_BODY_BYTES`, 256 KiB) 计数字节,而不是字符. 一个更大的内容 - Length 是 在读完任何内容之前被拒绝。 身体变长(被挤出,或被骗取头)被取消为 一旦超过限制,所以无尽的上传成本最多只能达到限制. 它拒绝的每个身体都被取消 在每一个出路 `readBody` 让我们去身体的溪流, 所以它从来没有被锁.
-   `message` 413个字 `'The photo is larger than 3 MB.'`。 。 。 .
-   Content- Type 被检查, 因为跨站点表单可以张贴 `text/plain` 没有飞行前,但没有 `application/json`。 。 。 . `anyContentType: true` 读取 `navigator.sendBeacon` 体 (单位:千人)`text/plain`;仅限打电话 没有饼干认证.
-   只有对象通过,而不是数组或赤值,所以 `const { name } = await readJson(request)` 无法 丢入类型错误.
-   `__proto__` 密钥被丢入每个深处, 所以 `Object.assign(row, body)` 无法改变原型.
-   `T` 是对编译器的保证,而不是检查:在使用字段之前先验证字段.

`streamBody` 将一个上传到商店而不保存在内存, R2 为一个:

```ts
const limit = { maxBytes: 100e6, message: 'An artifact is at most 100 MB.' }
await streamBody(request, limit, body => env.BUCKET.put(key, body))  // 411, 413, 400 when the upload broke
```

-   两次拒绝都会在字节读取前出现,并取消身体. 在工人中,溪流是一个 `FixedLengthStream`这样 R2知道它的长度.
-   断断续续的躯体, 或带来多少字节 比它的内容 - Length,错误流,所以商店 而不是保存一个剪接副本,而且 `streamBody` 丢出400 `unreadable_body`:发件人的错. 任何其他 商店的故障(它停止阅读,R2已倒下)是按原样扔出,一500.

## 谁打电话

-   `clientIp(request, fallback = 'unknown')`数字 : `cf-connecting-ip`云花板,没有人能伪造 通过它. `x-forwarded-for` 财务报告和审定财务报表 `x-real-ip` 永远不读.
-   `clientNetwork(request, fallback)`:按地址限制费率的密钥. IPv4地址保持完整. IPv6 地址 因为一个家庭或电话 持有整个64, 并且可以为每次尝试取一个新的地址. 地址的每个拼写都提供同样的钥匙 `::ffff:a.b.c.d` 给IPv4一个.
-   `requireSameOrigin(request, allowedOrigins)`:用于呼叫饼干认证。 它允许一个 `Origin` 这是 (b) 请求本身或所列(`http://localhost:5173` 或无 `Origin` 与 `Sec-Fetch-Site: same-origin`. 其他一切获得403 `cross_origin`,包括: `Origin: null` 没有标题 一点也不 它覆盖了WebSocket的升级,它们携带饼干跨站点. 所列条目不是来源 扔出类型错误.

## 费率限额

```jsonc
// wrangler.jsonc
"ratelimits": [{ "name": "AUTH_LIMITER", "namespace_id": "1001", "simple": { "limit": 10, "period": 60 } }]
```

`rateLimit(env.AUTH_LIMITER, key, { message, retryAfter })` 数到1个请求和429 `rate_limited` 与 `retry-after` (默认60,约束期限)一旦达到限制. 一个束缚 错误无法拒绝, 因此一个已断开的限制器拒绝请求, 而不是让每个人都通过 .

## 单页应用程序的页面

`"not_found_handling": "single-page-application"` 回答页面路径, 资产拼写为 307 到 他们自己的拼写。 他们解码每个段 并再次编码它与 `encodeURIComponent`数字 :

| 页面写 | 资产改用于 | 页面读取 |
| --- | --- | --- |
| `/Mac/search/house+of+the+dragon` | `/Mac/search/house%2Bof%2Bthe%2Bdragon` | 外加, 而不是空格 |
| `/rooms/AC%2FDC` | `/rooms/AC/DC` | 两个部分 |
| `/a//b` | `/a/b` | 减少一个部分 |
| `/s/a:b`, (中文(简体) ), `/s/%c5%82`, (中文(简体) ), `/s/100%` | `/s/a%3Ab`, (中文(简体) ), `/s/%C5%82`, (中文(简体) ), `/s/100%25` | 同样的文字,经过不必要的往返 |

`html_handling: "none"` 不变。 因此,一个将文本保留在路径中的应用程序(搜索,名称)读取 重装后的其他东西。 没有这种处理方式(`"none"`,默认值)资产回答路径为无 带有平地 404 的文件,从不重定向,路由器将其交给工人. `serveSinglePageApp` 接电话 与应用程序的页面,地址为:

```jsonc
// wrangler.jsonc
"assets": {
  "directory": "./dist",
  "binding": "ASSETS"
  // No not_found_handling: the Worker answers pages (serveSinglePageApp). Files never invoke the Worker.
}
```

```ts
async function route(request: Request, env: Env) {
  const path = new URL(request.url).pathname
  if (path.startsWith('/api/')) return (await handleApi(request, env)) ?? jsonError(404, 'Not found')
  return serveSinglePageApp(request, env.ASSETS) // last, for every path the API does not own
}
```

-   它首先要求资产获取路径: 他们的答案是文件, 他们的307 要求的文件由 另一种拼写方式 (`/sw%2Ejs` 改为 `/sw.js`, (中文(简体) ), `/index.html` 改为 `/`) (中文(简体) ). 只有404个成为了应用的一页,所以有效 相同的时候 `run_worker_first` 向工人发送文件( E)`true`,或 `["/*", "!/assets/*"]` 为工人 必须看到每个页面载荷),每个文件的工人引用.
-   与 `"single-page-application"` 资产会自己解决所有问题 把它拿出来.
-   只有GET和HEAD是页面。 任何其他方法投出405 `method_not_allowed` 与 `allow: GET, HEAD`,则 不要求资产.
-   页面是用请求的方法和标题询问的,所以重新装入 `If-None-Match` 仍然得到304.
-   `_headers` 规则适用于网页,如同适用于网页 `/`数字 : `/*` 规则确实如此,对于一个页面本身路径的规则没有. 保留页面 信头(CSP, `x-frame-options`继续 `/*`,或者把它们放在工人.
-   `{ shell: '/admin/' }` 用另一页的答案, 对于一个页面未在 `/`外壳不是 此站点的路径以 TypeError 拒绝 .

## 保存在缓存中的答案

`cachedJson` 用JSON来回答一个价格昂贵的或头部,对每个人都一样(目录,产品, (a) 价格清单)。 它将答案保存在工人的缓存中,所以大多数请求从不运行 `build`数字 :

```ts
import { cachedJson } from '@codefusion-cc/workers-http'

async function catalog(request: Request, env: Env, ctx: ExecutionContext) {
  const key = new URL('/api/catalog', request.url)                // one spelling of the question, however a visitor writes it
  return cachedJson(request, { cache: caches.default, waitUntil: (work) => ctx.waitUntil(work), maxAge: 60, staleFor: 600, key }, () => readTheCatalog(env.DB))
}
```

-   它发出 `application/json` 带有弱的ETag(正文的SHA-256)并 `cache-control: public, max-age=…, stale-while-revalidate=…`时 `max-age` 是保留答案的秒数。 请求 `If-None-Match` 名称当前 ETag( 微弱的比较, 列表, 或 `*`得到304 没有一具尸体.
-   虽然答案是新鲜的(在 `maxAge` 旧的) `build` 不运行。 过去的和内部 `staleFor` 保留答案 马上出去 `build` 在背景中运行一次 `waitUntil`; 查找同样僵硬答案的请求 在15秒内,没有第二次续约。 无 `waitUntil` 固态的答案在发送前被更新.
-   过去 `maxAge + staleFor`,或者没有保留任何东西, 请求等待 `build`,它的错误被抛出,因为 `errorResponse`如果 `build` 重现仍在其中的答案时抛出 `staleFor`,这个出去 `onError` 听说了`console.error` (默认情况下). 拒绝的缓存 `put` 失败 `match` 从不失败的答案.
-   `key` 答案被保存在那里。 默认是请求自己的地址,所以 `?a=1&b=2` 财务报告和审定财务报表 `?b=2&a=1` 有两个答案. 无 `cache` 没有任何东西被保存着,每一个请求都建立起来.
-   永远不要用它来回答因访客而异的答案(一个推车,一个会话,一个按账号计价的答案): `public`,则 第一个访客的回答会到达下一个.
-   仅限头部或头部 `maxAge` 至少为1和a `staleFor` 至少0整秒,并且一个值JSON可以 hold: 其它任何投出 TypeError, 因为这是一个编程错误 .

## 预览和制作

每个应用程序自行部署两本,预览和制作(tools/ci). `answerCopy` 财务报告和审定财务报表 `markCopy` 让每个 说出是哪一个,并把它排除在搜索结果之外:

```ts
import { answerCopy, type CopyEnv, markCopy } from '@codefusion-cc/workers-http'

export default {
  fetch: async (request: Request, env: Env) => markCopy(answerCopy(request, env) ?? await answer(request, env), env),
}
```

-   `answerCopy` 答案获取和标题 `/version.json` 与 `{ commit, environment }` (单位:千美元)`COMMIT`,该部署 套装和 `APP_ENV` 从抄本"Wrangler vars";无所取用),并 `/robots.txt`。所有其他请求 这是无效的,所以它保持应用的。 部署和小时生产表都读了.
-   `markCopy` 添加 `X-Robots-Tag: noindex, nofollow` 对每一个答案,和 `/robots.txt` 拒绝一切, 除非应用程序通过 `{ indexed: true }` 财务报告和审定财务报表 `APP_ENV` 没错 `production`预览,缺少 `APP_ENV` 或者里面的打字没有搜索结果 一个WebSocket升级的通行证是它是什么。 网站的静态文件从不 以工人们所享受的 `_headers` 发送相同的信头.

## 饼干和大麻

```ts
getCookie(request, '__Host-session')                                  // string, or null (missing or empty)
serializeCookie('__Host-session', token, { maxAge: 30 * 86_400 })     // Path=/; Max-Age=…; HttpOnly; Secure; SameSite=Lax
serializeCookie('__Host-session', '', { maxAge: 0 })                  // clears it
await sha256(token)                                                   // 64 hex characters
await sha256(token, 'base64url')                                      // 43 characters
```

`serializeCookie` 丢弃浏览器会拒绝或错误读取的内容: 带有空格、 引号、 逗号的值, 分号或反斜线(先编码), `SameSite=None` 或一个 `__Host-`编号 :`__Secure-` 无名称 `secure`页:1 `__Host-` 名称带有域或其它路径。 留一个 `sha256` 每被存储一列编码:两者不相匹配.

## 在应用测试中

```ts
import { testRateLimiter } from '@codefusion-cc/workers-http/testing'

const limiter = testRateLimiter({ limit: 2 })       // or { fail: new Error('down') }
await rateLimit(limiter, 'k'); await rateLimit(limiter, 'k')
await expect(rateLimit(limiter, 'k')).rejects.toMatchObject({ status: 429 })
limiter.keys // ['k', 'k', 'k']
```

```ts
import { testAssets } from '@codefusion-cc/workers-http/testing'

const assets = testAssets({ files: { '/index.html': '<!doctype html>…', '/sw.js': '…' } }) // or { fail: new Error('down') }
await worker.fetch(new Request('https://app.test/Mac/search/a+b'), { ...env, ASSETS: assets })
assets.paths // ['/Mac/search/a+b', '/']: what was asked; assets.requests holds the requests
```

`testAssets` 回答如静态资产 `not_found_handling: "none"`: 路径文件和文件夹 `index.html` 在文件夹,一个307 来自任何其他拼写 两者,一个404 对于一个路径,没有文件, 405 对于其他 在文件上使用方法,在 ETag 上使用 304。 货包的工人测试 把它控制在真正的约束.

运行工人的测试 使用真正的约束 从Wrangler配置.

## 常见问题

### @codefusion-cc/workers-http 是什么？

Cloudflare Worker的API的HTTP管道: 错误被抛出作为答案, API的路线, JSON 的响应, 绑定了 JSON 和身体读取, 客户端的地址和网络, 同源检查, 费率限制 a RatLimit 绑定, cookie, SHA-256 和 a s

### 如何安装 @codefusion-cc/workers-http？

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

### @codefusion-cc/workers-http 支持 TypeScript 吗？

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

### @codefusion-cc/workers-http 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @codefusion-cc/workers-http 需要什么版本的 Node\.js？

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

### @codefusion-cc/workers-http 可以商用吗？

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

### @codefusion-cc/workers-http 的下载量有多少？

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

### @codefusion-cc/workers-http 还在维护吗？

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

