六维教程

Cloudflare Workers 请求与响应

这一篇深入 Workers 的核心编程模型。掌握了 Request 和 Response,你就掌握了 Workers 的骨架,后面所有功能都是在这个骨架上生长出来的。

入口函数

Workers 的代码统一从 fetch 函数进入

export default {
  async fetch(request, env, ctx) {
    return new Response("Hello");
  },
};

每次有 HTTP 请求进来,平台就会调用一次 fetch 函数,传入三个参数

参数 作用
request 请求对象,只读,描述”用户想要什么”
env 环境对象,读取环境变量和数据库等绑定资源
ctx 上下文对象,管理后台任务等生命周期

如果你看过一些老教程,可能会见到 addEventListener("fetch", ...) 的写法,那是早期的 Service Worker 语法,现在已经不推荐,统一用上面的模块写法。

Request 请求对象

request 保存了用户请求的全部信息,常用属性如下

属性 说明
method 请求方法,GET、POST、PUT、DELETE 等
url 完整请求地址,含查询参数
headers 请求头,可用 get() 读取单个头
body 请求体(GET 请求通常为空)

读取请求头的示例

export default {
  async fetch(request, env, ctx) {
    const userAgent = request.headers.get("User-Agent");
    return new Response(`你的浏览器是 ${userAgent}`);
  },
};

请求体读取规则

POST、PUT 请求通常会携带请求体,Workers 提供了四种读取方式

// 按文本读取
const text = await request.text();

// 按 JSON 读取(请求体是 JSON 时)
const data = await request.json();

// 按表单读取(请求体是表单时)
const form = await request.formData();

// 按二进制读取
const buffer = await request.arrayBuffer();

有一条重要规则要记住,请求体只能读取一次。第一次调用后内容就会被消费掉,再次读取会报错。如果需要读取两次(比如既要解析 JSON 又要保留原内容转发),先调用 request.clone() 复制一份再分别读取

export default {
  async fetch(request, env, ctx) {
    const copy = request.clone();
    const data = await request.json();
    // 用 copy 继续做别的处理
    return new Response("ok");
  },
};

Response 响应对象

返回响应有三种常见方式

// 方式一,new Response 构造
return new Response("hello", {
  status: 200,
  headers: {
    "Content-Type": "text/plain",
  },
});

// 方式二,返回 JSON
return Response.json({ name: "Alice", age: 20 });

// 方式三,重定向
return Response.redirect("https://example.com", 302);

new Response 的第一参数是响应体,第二参数可以设置状态码和响应头。记住几个常用状态码

状态码 含义
200 成功
301/302 重定向
404 资源不存在
405 请求方法不允许
500 服务器内部错误

错误处理

代码运行中出现异常时,平台会返回 500 错误。实际开发中要自己捕获异常并返回合理的响应

export default {
  async fetch(request, env, ctx) {
    try {
      const data = await request.json();
      return Response.json({ received: data });
    } catch (err) {
      return Response.json({ error: "请求体不是合法的 JSON" }, { status: 400 });
    }
  },
};

捕获异常后手动设置状态码返回给用户,比让平台返回笼统的 500 更友好,也方便前端做针对性处理。

后台任务 ctx.waitUntil

有时候响应已经可以返回,但还有一些收尾工作要做,比如写日志、发统计、清理缓存。这些工作不需要用户等待,可以直接用 ctx.waitUntil 挂到后台执行

export default {
  async fetch(request, env, ctx) {
    // 先记录日志,不阻塞用户
    ctx.waitUntil(logRequest(request.url));
    return new Response("ok");
  },
};

async function logRequest(url) {
  // 模拟写日志,这里耗时不影响用户
  await fetch("https://log-service.example.com", {
    method: "POST",
    body: url,
  });
}

ctx.waitUntil 接受一个 Promise,函数返回后平台会等待这些后台任务完成再回收资源。

发起子请求 fetch

Workers 内部可以直接发起 HTTP 请求访问其他服务,包括你自己的其他 API 或第三方接口,这就是子请求

export default {
  async fetch(request, env, ctx) {
    const resp = await fetch("https://api.github.com/repos/cloudflare/workers-sdk", {
      headers: { "User-Agent": "my-worker" },
    });
    const data = await resp.json();
    return Response.json({ stars: data.stargazers_count });
  },
};

子请求返回的是一个标准 Response 对象,可以用同样的方式读取内容。注意免费计划每次请求最多发起 50 个子请求,需要并发请求多个接口时建议用 Promise.all 合并,避免串行拖慢速度。

这些基础能力组合起来,已经能实现大多数接口逻辑。下一篇用它做一个带路由的多接口服务。

上一篇 Cloudflare Workers 开发工作流
下一篇 Cloudflare Workers 路由与 API 开发

上一篇
Cloudflare Workers 开发工作流
下一篇
Cloudflare Workers 路由与 API 开发