首页
/ Puter Worker 路由(router)开发指南:定义 HTTP 接口、读取双上下文并操作共享存储

Puter Worker 路由(router)开发指南:定义 HTTP 接口、读取双上下文并操作共享存储

2026-09-08 16:22:46作者:董宙帆

Puter Worker 采用基于 router 的路由体系处理 HTTP 请求——router 对象在 Worker 代码中自动可用,用于把不同的 URL 路径与方法分发给对应的处理函数。本文以此官方文档 router.md 为主体,结合仓库内 Worker 运行时源码(s2w-router.js)、类型声明(router.d.ts)与客户端 SDK(Workers.js)展开讲解。读完本文,你将掌握:如何用 router 注册 GET/POST/PUT/DELETE/OPTIONS 端点、如何捕获路径参数与通配路径、CORS 的自动处理规则,以及如何在一个 Worker 中同时操作"调用者数据"(user.puter)与"Worker 属主数据"(me.puter)实现 User-Pays 计费与共享服务逻辑。

Router 是什么:Worker 的 HTTP 请求分发中心

Puter Worker 是部署在 Puter 上的无服务器计算单元,接收外部 HTTP 请求并执行服务端逻辑。与直接监听 fetch 事件不同,Puter Worker 默认把请求交给全局 router 对象统一调度。当你基于 JS 文件部署 Worker 后(部署方式见 create.md),运行时会自动注入一个带路由能力的运行时,见 index.js

import initS2w from './s2w-router.js';
initS2w();

initS2w()(server-to-worker 路由)完成两件事:构造 router 并挂到 globalThis.router 上,然后注册一个 fetch 事件监听器,把所有请求交给 router.route(event) 处理(见 s2w-router.js):

globalThis.router = router;
self.addEventListener('fetch', (event) => {
    if (!router.routing) {
        return false;
    }
    event.respondWith(router.route(event));
    return true;
});

因此你的 Worker 源码不需要任何 import 语句,直接使用 router 即可。一个最简端点长这样:

router.post("/my-endpoint", async ({ request, user, params }) => {
  return { message: "Hello, World!" };
});

处理器返回的普通对象会被运行时自动序列化为 JSON 响应,无需手动构造 Response

支持的标准 HTTP 方法

router 为常用 HTTP 动词提供了同名注册方法,签名统一为 router.<method>(path, handler)

  • router.get(path, handler) —— 处理 GET 请求
  • router.post(path, handler) —— 处理 POST 请求
  • router.put(path, handler) —— 处理 PUT 请求
  • router.delete(path, handler) —— 处理 DELETE 请求
  • router.options(path, handler) —— 处理 OPTIONS 请求(会接管预检处理,见下文 CORS 章节)

从源码看(s2w-router.js),这些方法内部都委托给同一个 custom(eventName, route, eventListener):按 HTTP 方法名把"路由匹配器 + 处理函数"追加进 router.map(一个 Map,键为请求方法,值为匹配器数组)。因此还额外暴露了 router.custom(method, path, handler),可注册任意 HTTP 方法。类型声明见 router.d.ts

/**
 * Register a handler for an arbitrary HTTP method (e.g. `PATCH`, `HEAD`).
 * The other verb methods all delegate to this internally.
 */
custom<S extends string>(method: string, path: S, handler: ...): void;

例如注册 PATCH 端点:router.custom('PATCH', '/posts/:id', ({ params }) => ({ patched: params.id }))(该写法在 example.worker.ts 的类型冒烟测试中出现过)。

此外,router 上还有两个运行时可调开关(见 router.d.ts):

  • routing: boolean —— 默认 true。置为 false 后 Worker 停止处理 fetch 事件(index.jsrouter.routing 为假时直接跳过请求)。
  • handleCors: boolean —— 默认 true。为 true 时由路由自动应答预检 OPTIONS,并为缺少 Access-Control-Allow-Origin 的响应自动补上 *false 则全部交由你自己的处理器决定。

处理器参数(Handler Parameters)

每个路由处理函数接收一个参数对象,通常解构出以下三个属性:

  • request —— 进来的 HTTP 请求,是 Web 标准的 Request 对象,可用 request.urlrequest.json()request.formData()request.headers.get(...) 等方法读取请求信息。
  • user —— 发起该请求的用户对象。user.puter 允许访问该用户自己的 Puter 资源(KV、FS、AI 等)。仅当 Worker 通过 puter.workers.exec() 被调用、并携带用户 token 时才会出现
  • params —— 从路径中捕获的路由参数对象(见下文"路径参数")。

运行时传给处理函数的事件对象本质上是 WorkerEvent,其类型定义(event.d.ts)完整反映了这一点:

export interface WorkerEvent<TParams extends Params = Params> extends Extendable {
    request: Request;
    params: TParams;
    user?: PuterContext;   // 仅当带 puter-auth 头调用时存在
    waitUntil(f: Promise<any>): void;
}

注意:user 在类型上是可选的(user?),代码里必须先判空再访问 user.puter,否则在匿名 HTTP 调用下会抛错。事件对象上还有与 ExtendableEvent.waitUntil() 语义一致的 waitUntil(),可用来让 Worker 持续运行到某个后台任务结束。

全局对象(Global Objects)

编写 Worker 时可直接访问以下全局对象:

  • router —— 用于定义 API 端点的路由器对象。
  • me —— 代表你自己,即 Worker 的属主me.puter 允许访问你自己的 Puter 资源(KV、FS、AI 等)。
  • mymyself —— me 的兼容别名(已标记 deprecated,未来会移除)。
  • puter_authputer_endpoint —— 旧版环境绑定,分别对应部署者的 Puter auth token 与 API 端点(默认 https://api.puter.com),同样已标记 deprecated。

全局声明见 globals.d.ts。从运行时源码看,meuser 都是在 router.route(event) 入口处被注入的(s2w-router.js):

async route(event) {
    // 1) 首次调用时初始化属主上下文 me,使用 Worker 自己的凭据
    if (!globalThis.me) {
        globalThis.me = {
            puter: init_puter_portable(
                globalThis.puter_auth,
                globalThis.puter_endpoint || 'https://api.puter.com',
                'userPuter',
            ),
        };
        globalThis.my = me;
        globalThis.myself = me;
    }
    // 2) 若请求头携带 puter-auth,则注入调用者上下文 user
    if (event.request.headers.has('puter-auth')) {
        event.requestor = {
            puter: init_puter_portable(
                event.request.headers.get('puter-auth'),
                globalThis.puter_endpoint || 'https://api.puter.com',
                'userPuter',
            ),
        };
        event.user = event.requestor;
    }
    ...
}

这段代码印证了文档的描述:me 永远是 Worker 属主,user 是否存在取决于请求是否带了 puter-auth 头。

路由匹配的底层原理

为了帮你准确理解路径参数与通配符的边界行为,这里展开运行时 buildRouteMatcher 的实现(s2w-router.js)。它把用户写的路由字符串编译成正则表达式:

  • 普通字符会被 escapeRegex 转义后原样保留;
  • 遇到 : 开头的一个参数名(由 [A-Za-z0-9_] 字符连续组成),编译为 ([^/]+),即匹配单个路径段、不含斜杠
  • 遇到 * 开头的一个参数名,编译为 (.*),即贪婪匹配剩余任意字符(可含斜杠)
  • 如果 :* 后面没有任何合法名称字符,则当作普通字面量转义保留——这正是文档强调"裸 * 不生效、必须命名"的原因;
  • 正则整体以 ^ 开头、$ 结尾,即整条 pathname 必须完全匹配。

每个已注册的方法都保存这样一个"匹配器 + 处理器"对。请求到达后按方法取出映射,逐个对 url.pathname 执行 regex.exec,命中即把捕获组写入 event.params 并调用处理器(s2w-router.js);全部未命中则返回 404 "Path not found";处理器抛错则被捕获并返回 500。

处理器返回值自动包装

运行时对处理器的返回值有一套自动包装逻辑(s2w-router.js):

  • 返回 Response 对象:原样使用;
  • 返回 BlobArrayBufferUint8ArrayReadableStreamURLSearchParams字符串:自动 new Response(value) 包装;
  • 返回普通对象/数组/其他可 JSON 序列化值JSON.stringify 后包装为 Content-Type: application/json 的响应;
  • 以上都包装失败:抛错,最终由外层兜底为 500 响应。

对应类型定义在 event.d.tsHandlerReturn 中:Response | string | Blob | ArrayBuffer | Uint8Array | ReadableStream | URLSearchParams | Record<string, unknown> | unknown[] | number | boolean | null。理解这套规则后,下面各种返回值的写法就一目了然了。

路径参数(Route Parameters)

路径中并非每一段都是固定值(如文章 ID、用户名)。把这些段用冒号 : 前缀命名,即可捕获到 params 对象上,键名为你给的名字:

router.get("/api/posts/:category/:id", async ({ params }) => {
  const { category, id } = params;
  return { category, id };
});

请求 /api/posts/tech/42 命中该路由后:

  • params.category"tech"
  • params.id"42"

参数数量不限。捕获到的值永远是字符串——如果期望的是数字,记得自行转换(如 Number(params.id))。

从源码层面看,:category:id 被编译为两个独立的 ([^/]+) 捕获组,值按名称顺序填入 params。类型层面,运行时类型声明能直接从路径字面量推导出 params 的类型:ExtractParams<'/posts/:id'> 被解析为 { id: string }(见 params.d.ts),因此写 TypeScript 时无需手动标注 params.id 的类型(该特性在 example.worker.ts 的类型冒烟测试中有体现)。

通配符路由(Wildcard Routes)

路径参数 :name 只匹配单个路径段,而通配符 *name 匹配剩余整段路径——任意数量的段。与路径参数一样,匹配值会以 * 后面的名字作为键出现在 params 上:

router.get("/files/*path", async ({ params }) => {
  // 请求 /files/images/avatars/me.png 时:
  // params.path === "images/avatars/me.png"
  return { path: params.path };
});

两条必须记住的规则:

  1. 通配符必须命名——写 *path(名字随意),不能写裸 *。裸 * 因为没有后续名称字符,在 buildRouteMatcher 里被当作字面量转义,路由只会精确匹配路径 /files/* 而不会匹配任何子路径(这正是文档明确警告的行为)。
  2. 通配符路由是"兜底"手段——捕获型匹配器按注册顺序逐一尝试,通配符贪婪匹配所有剩余路径,因此应把 catch-all 路由定义在最后,确保只在其他路由都未命中时才执行。一个典型的 404 Handler 就长这样(放最后):
    • 通用 GET 兜底:router.get("/*page", ...)
    • 若需要同时兜底所有方法,可对每种方法分别注册兜底,或用 router.custom 配合方法判断。

CORS:默认自动处理

CORS 由运行时自动处理,你通常无需写任何 CORS 代码:

  • 每个响应都会自动带上 Access-Control-Allow-Origin: *(若响应尚未含有该头,运行时会在返回前补上,见 s2w-router.js);
  • 预检 OPTIONS 请求被自动应答。当收到带 OriginAccess-Control-Request-MethodAccess-Control-Request-Headers 的 OPTIONS 请求且该 Worker 没有自定义 OPTIONS 路由时,默认的 handleOptions 会返回包含 Access-Control-Allow-Origin: *Access-Control-Allow-Methods: GET,HEAD,POST,PUT,DELETE,OPTIONSAccess-Control-Max-Age: 86400 的 204 应答,并回显请求方申请的 Access-Control-Allow-Headers(见 s2w-router.js)。

这意味着跨域调用开箱即用——包括 puter.workers.exec():它会把调用者的 Puter token 放进自定义请求头 puter-auth 发给 Worker(user.puter 正是由这个头注入的),全程不需要你处理任何 CORS。

唯一的例外:如果你自己定义了 OPTIONS 处理器,就等于接管了预检应答,这时浏览器期望的响应头需要你自己负责。例如:

router.options("/*path", async () => {
  return new Response(null, {
    status: 204,
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
      "Access-Control-Allow-Headers": "Content-Type, Authorization, puter-auth",
    },
  });
});

警告:如果你覆盖了预检处理,并且 Worker 仍要通过 puter.workers.exec() 调用,那么必须把 puter-auth 列入 Access-Control-Allow-Headers——否则预检失败,请求根本到不了你的 Worker。

双上下文编程:me.puteruser.puter

与普通 App/网站一样,Worker 里也能使用 Puter.js 访问 AI、云存储、KV、数据库。区别在于用的是谁的资源:Worker 暴露给你两个 .puter 对象,每次操作记在调用它的那个账户头上:

  • me.puter(Worker 上下文 / 属主上下文):Worker 属主自己的资源。适合存放共享的应用数据、服务端逻辑与集中式资源。操作跑在属主账户上,费用记在属主名下
  • user.puter(用户上下文):调用该 Worker 的用户的资源(仅当通过 puter.workers.exec() 以用户 token 执行时可用)。它保持了默认的 User-Pays(用户付费)模型:每个用户的数据留在自己的存储、费用记在自己账上,而你的服务端逻辑照常执行。

因此你可以在同一份代码里混用两者——某些端点读写自己的数据(me.puter),另一些端点操作调用者数据(user.puter),费用互不混淆。

从客户端实现看,puter.workers.exec() 的本质(Workers.js)是"fetch + 自动附加会话头":

async exec (...args) {
    await this.#authenticateIfNeeded();
    const req = new Request(...args);
    if ( ! req.headers.get('puter-auth') && !req.headers.get('x-puter-no-auth')) {
        req.headers.set('puter-auth', this.puter.authToken);
    }
    req.headers.delete('x-puter-no-auth');
    return fetch(req);
}

它接受与 Fetch API 相同的 (input, init?) 参数并返回 Response。如果需要"不带会话"地调用(即不让 Worker 获得用户上下文),显式传入 x-puter-no-auth 头即可跳过 puter-auth 注入。

常用端点写法速查

以下是官方文档给出的各类常见写法,覆盖请求读取与响应构造的所有常规形态。

基础 GET 端点

router.get("/api/hello", async ({ request }) => {
  // Simple GET endpoint
  return { message: "Hello, World!" };
});

读取 JSON 请求体

router.post("/api/user", async ({ request }) => {
  // Get JSON body
  const body = await request.json();
  return { processed: true };
});

读取表单数据(multipart/form-data)

router.post("/api/user", async ({ request }) => {
  // Get form data
  const formData = await request.formData();
  return { processed: true };
});

读取查询参数

router.get("/api/search", async ({ request }) => {
  // Read query string parameters from the URL
  const url = new URL(request.url);
  const query = url.searchParams.get("q");
  return { query };
});

读取请求头

router.post("/api/user", async ({ request }) => {
  // Get headers
  const contentType = request.headers.get("content-type");
  return { processed: true };
});

带路径参数

router.get("/api/posts/:category/:id", async ({ request, params }) => {
  const { category, id } = params;
  return { category, id };
});

各类响应形态

根据前文"返回值自动包装"规则,以下几种写法都合法:

// JSON 响应(对象自动转 JSON)
router.get("/api/simple", async ({ request }) => {
  return { status: "ok" }; // Automatically converted to JSON
});

// 纯文本响应
router.get("/api/text", async ({ request }) => {
  return "Hello World"; // Returns plain text
});

// Blob 响应
router.get("/api/blob", async ({ request }) => {
  return new Blob(["Hello World"], { type: "text/plain" });
});

// Uint8Array 响应(字节内容:"Hello World")
router.get("/api/uint8array", async ({ request }) => {
  return new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);
});

// 二进制流响应
router.get("/api/binary-stream", async ({ request }) => {
  return new ReadableStream({
    start(controller) {
      controller.enqueue(
        new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100])
      );
      controller.close();
    },
  });
});

// 完全自定义的 Response 对象(状态码 + 自定义头)
router.get("/api/custom", async ({ request }) => {
  return new Response(JSON.stringify({ data: "custom" }), {
    status: 200,
    headers: {
      "Content-Type": "application/json",
      "Custom-Header": "value",
    },
  });
});

返回自定义错误响应

Response 设置状态码与响应头即可精确控制错误语义:

router.post("/api/risky-operation", async ({ request }) => {
  try {
    const body = await request.json();
    const result = await someRiskyOperation(body);
    return { success: true, result };
  } catch (error) {
    return new Response(
      JSON.stringify({
        error: "Operation failed",
        message: error.message,
      }),
      {
        status: 500,
        headers: { "Content-Type": "application/json" },
      }
    );
  }
});

实战整合:与 Puter 资源的双向打通

下面几组示例演示 Worker 最有价值的用法——把"请求处理"和"属主/调用者的 Puter 资源"串起来。

Worker 上下文 vs 用户上下文

同一类操作可以分别跑在两个账户上。下面两个端点分别从调用者 KV 与属主 KV 读值:

// 从调用者的 KV 存储读取(user context)
router.get("/api/kv/user/get", async ({ request, user }) => {
  const url = new URL(request.url);
  const key = url.searchParams.get("key");
  const value = await user.puter.kv.get(key);
  return { value };
});

// 从 Worker 属主的 KV 存储读取(worker context)
router.get("/api/kv/worker/get", async ({ request }) => {
  const url = new URL(request.url);
  const key = url.searchParams.get("key");
  const value = await me.puter.kv.get(key);
  return { value };
});

文件系统(FS)集成:接收上传

router.post("/api/upload", async ({ request }) => {
  const formData = await request.formData();
  const file = formData.get("file");

  if (!file) {
    return new Response(JSON.stringify({ error: "No file provided" }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  const fileName = `upload-${Date.now()}-${file.name}`;
  await me.puter.fs.write(fileName, file);

  return {
    uploaded: true,
    fileName,
    originalName: file.name,
    size: file.size,
  };
});

KV 集成(含命名空间前缀与 404 语义)

一个值得借鉴的实践:Worker 属主与调用者共享同一账户的 KV 时,用固定前缀隔离不同数据域,避免误读调用者的其他业务数据:

router.post("/api/kv/set", async ({ request }) => {
  const { key, value } = await request.json();

  if (!key || value === undefined) {
    return new Response(JSON.stringify({ error: "Key and value required" }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  await me.puter.kv.set("myscope_" + key, value); // 加前缀,避免盲读到用户的其他 KV 数据
  return { saved: true, key };
});

router.get("/api/kv/get/:key", async ({ request, params }) => {
  const key = params.key;
  const value = await me.puter.kv.get("myscope_" + key); // 读取时用同一前缀

  if (!value) {
    return new Response(JSON.stringify({ error: "Key not found" }), {
      status: 404,
      headers: { "Content-Type": "application/json" },
    });
  }

  return { key, value: value };
});

AI 集成:鉴权 + 双上下文配合

这个例子同时示范了三件事:用 user 判空做鉴权拦截(防止匿名滥用)、用调用者的 AI 资源完成对话(费用记在用户头上)、再用属主 KV 记录审计/分析数据:

router.post("/api/chat", async ({ request, user }) => {
  const { message } = await request.json();

  if (!message) {
    return new Response(JSON.stringify({ error: "Message required" }), {
      status: 400,
      headers: { "Content-Type": "application/json" },
    });
  }

  // 要求用户鉴权,防止滥用
  if (!user || !user.puter) {
    return new Response(
      JSON.stringify({
        error: "Authentication required",
        message:
          "This endpoint requires user authentication. Call this worker via puter.workers.exec() with your user token to use your own AI resources.",
      }),
      {
        status: 401,
        headers: { "Content-Type": "application/json" },
      }
    );
  }

  try {
    // 使用调用者的 AI 资源
    const aiResponse = await user.puter.ai.chat(message);

    // 把聊天历史记到开发者自己的 KV,用于分析
    const chatHistory = {
      userId: user.id || "unknown",
      message,
      response: aiResponse,
      timestamp: new Date().toISOString(),
      usedUserAI: true,
    };
    await me.puter.kv.set(`chat_${Date.now()}`, chatHistory);

    return {
      originalMessage: message,
      aiResponse,
      usedUserAI: true,
    };
  } catch (error) {
    return new Response(
      JSON.stringify({
        error: "AI service error",
        message: error.message,
      }),
      {
        status: 500,
        headers: { "Content-Type": "application/json" },
      }
    );
  }
});

404 Handler:始终为未匹配路径兜底

推荐始终为未匹配路径提供一个兜底路由,返回结构化的 404 而非裸错误。兜底通配路由要注册在所有具体路由之后

router.get("/*page", async ({ request, params }) => {
  const requestedPath = params.page;

  return new Response(
    JSON.stringify({
      error: "Not found",
      path: requestedPath,
      message: "The requested endpoint does not exist",
      availableEndpoints: ["/api/hello", "/api/data", "/api/upload"],
    }),
    {
      status: 404,
      headers: { "Content-Type": "application/json" },
    }
  );
});

补充说明:即便不写兜底路由,运行时也会为未命中路径返回 404 "Path not found"、为"方法存在但该请求方法没有路由"返回 404 "No routes for given request type ..."(见 s2w-router.js);自定义兜底的价值在于提供更友好的业务化提示。若想区分不同方法,可对 postput 等分别注册 /*page 兜底。

完整示例:一个多端点 Worker

以下是一个聚合了健康检查、用户管理、文件上传与兜底 404 的完整 Worker,几乎覆盖了 router 的全部常用模式。注意示例中刻意做了两点防护:写入 KV 的 key 一律使用 user_ 前缀并在读取时校验,防止任意读/写内部键:

// 健康检查
router.get("/health", async () => {
  return {
    status: "ok",
    timestamp: new Date().toISOString(),
  };
});

// 用户管理 API
router.post("/api/users", async ({ request, user }) => {
  const userInfo = await user.puter.getUser();

  // 存储用户数据(写入属主 KV)
  const userId = `user_${Date.now()}`;
  await me.puter.kv.set(userId, {
    email: userInfo.email,
    name: userInfo.username,
  });

  return {
    userId,
    user: {
      email: userInfo.email,
      username: userInfo.username,
      uuid: userInfo.uuid,
    },
  };
});

router.get("/api/users/:id", async ({ params }) => {
  const userId = params.id;
  if (!userId.startsWith("user_"))
    // security check:防止读取任意 KV 键
    return new Response("Invalid userID!");
  const userData = await me.puter.kv.get(userId);

  if (!userData) {
    return new Response(
      JSON.stringify({
        error: "User not found",
      }),
      {
        status: 404,
        headers: { "Content-Type": "application/json" },
      }
    );
  }

  return { userId, user: userData };
});

// 文件操作
router.post("/api/files/upload", async ({ request }) => {
  const formData = await request.formData();
  const file = formData.get("file");

  if (!file) {
    return new Response(
      JSON.stringify({
        error: "No file provided",
      }),
      {
        status: 400,
        headers: { "Content-Type": "application/json" },
      }
    );
  }

  const fileName = `upload-${Date.now()}-${file.name}`;
  await me.puter.fs.write(fileName, file);

  return {
    uploaded: true,
    fileName,
    originalName: file.name,
    size: file.size,
  };
});

// 404 兜底:始终放在最后
router.get("/*tag", async ({ params }) => {
  return new Response(
    JSON.stringify({
      error: "Not found",
      path: params.tag,
      availableEndpoints: ["/health", "/api/users", "/api/files/upload"],
    }),
    {
      status: 404,
      headers: { "Content-Type": "application/json" },
    }
  );
});

安全提醒(从示例中可以提炼出的通用规范):

  • me.puter 持有集中式共享状态时,所有 KV 键设计为带业务前缀的受控命名空间,并由服务端自己拼接,不直接信任外部传来的完整键名;
  • 对外暴露按 ID 读取资源的端点时,先校验 ID 格式(如 startsWith("user_"))再落库查询;
  • 需要调用者身份/数据时,先判 user 是否存在,缺失即返回 401 引导走 puter.workers.exec()

部署后如何测试你的 Router

部署 Worker 后,可以在任意网站/App(含 Node.js 环境,均可调用 puter.workers 模块)里用 puter.workers.exec() 验证端点。它会自动带上调用者的会话(puter-auth 头),从而同时测出 user context 是否正常注入:

// 测试你的 Worker 端点
const workerUrl = "https://your-worker.puter.work";

// 测试 GET 端点
const response = await puter.workers.exec(`${workerUrl}/api/hello`);
const data = await response.json();
console.log(data);

// 测试 POST 端点
const postResponse = await puter.workers.exec(`${workerUrl}/api/data`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ key: "test", value: "hello" }),
});
const postData = await postResponse.json();
console.log(postData);

若想测试"无会话调用",按 Workers.js 的实现可显式添加 x-puter-no-auth 头,此时 user 上下文不会被注入,可用于验证 Worker 对匿名请求的兜底行为。Worker 的创建、查询、删除与日志流分别见 create.mdget.mdlist.mddelete.md,完整的运行时参数类型见 types.mdworker-types 目录下的声明文件。

小结

Puter Worker 的 router 是一个功能完整但极简的 HTTP 路由层:五种标准方法 + custom 兜底所有动词、: 捕获单段参数、*name 贪婪匹配剩余路径、自动 CORS 与自动响应包装,再加上 me.puter / user.puter 双上下文。理解匹配器的正则语义(单段 vs 多段、裸 * 是字面量)与运行时注入规则(puter-auth 头决定 user 是否存在),就能写出既安全又能精确控制计费归属的 Worker API。建议动手改一改 example.worker.ts 里的冒烟用例,在真实仓库中验证你理解的各种边界行为。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391