发送响应

H3 会自动将任何返回值转换为 web 响应。

从 事件处理器 返回的值会被 H3 自动转换为 web 的 Response。

示例: 简单事件处理函数。

const handler = defineHandler((event) => ({ hello: "world" }));

H3 会智能转换该处理器为:

const handler = (event) =>
  new Response(JSON.stringify({ hello: "world" }), {
    headers: {
      "content-type": "application/json;charset=UTF-8",
    },
  });

Tip

🚀 H3 内部使用 srvx 的 FastResponse 来优化 Node.js 运行时的性能。

如果事件处理器返回一个 Promise 或来源于 async 函数,H3 会等待其完成后再发送响应。

如果抛出错误,H3 会自动用错误处理器进行处理。

Read more in 错误处理.

#准备响应

在主处理器返回响应之前,可以使用 event.res 来准备响应头和状态。

defineHandler((event) => {
  event.res.status = 200;
  event.res.statusText = "OK";
  event.res.headers.set("Content-Type", "text/html");
  return "<h1>Hello, World</h1>";
});

Note

如果返回完整的 Response 值,则准备好的状态会被丢弃,响应头将被合并或覆盖。出于性能考虑,在这种情况下,最好只从最终的 Response 中设置响应头。

Note

如果发生错误,准备好的状态和头信息将被丢弃。推荐的方式是通过 new HTTPError({ headers }) 在错误响应中包含头信息。作为最后的手段,对于需要在错误确定之前隐式设置的头信息(例如 CORS),可以使用 event.res.errHeaders——这些会自动合并到错误响应中。

#响应类型

H3 会智能将 JavaScript 值转换为 web 的 Response。

#可序列化为 JSON 的值

返回一个可通过 JSON 序列化的值(对象、数组、数字或 布尔值)时,H3 会使用 JSON.stringiffy() 进行序列化,并以默认的 application/json 内容类型发送。

示例:

app.get("/", (event) => ({ hello: "world" }));

Tip

返回的对象若含有 .toJSON() 属性,可以自定义序列化行为。详情可参考 MDN 文档。

#字符串

返回字符串时,内容会作为纯文本体发送。

Note

如果未设置 content-type 头,默认类型为 text/plain;charset=UTF-8。

示例: 发送 HTML 响应。

app.get("/", (event) => {
  event.res.headers.set("Content-Type", "text/html;charset=UTF-8");
  return "<h1>hello world</h1>";
});

也可以使用 html 工具作为快捷方式。标签模板中的插值会自动进行 HTML 转义,以帮助防止 XSS。

import { html, raw } from "h3";

// 标签模板:插值会进行转义
app.get("/hello/:name", (event) => html`<h1>hello ${event.context.params.name}</h1>`);

// 可信标记:按原样发送
app.get("/", () => html(raw("<h1>hello world</h1>")));

Important

使用普通字符串调用 html() 时,整个字符串都会进行转义(如果转义改变了字符串内容,则会记录警告)。对于动态值,请使用标签模板;对于可信标记,请使用 raw() 包装。

#Response

返回 web Response 时,会将其作为最终响应发送。

示例:

app.get("/", (event) => new Response("Hello, world!", { headers: { "x-powered-by": "H3" } }));

Important

发送 Response 时,之前设置的任何已准备响应头都会合并为默认响应头。event.res.{status,statusText} 将被忽略。出于性能考虑,最好只在最终的 Response 中设置响应头。

如果返回的 Response 具有错误状态(>= 400),则已准备的响应头会被丢弃——这与抛出错误时相同——并且只会合并 event.res.errHeaders。成功响应和重定向响应(< 400)会接收所有已准备的响应头,因此在返回 302 之前调用 setCookie() 可以按预期工作。

#ReadableStream 或 Readable

返回 ReadableStream 或 Node.js 的 Readable 即以流的形式发送。

#ArrayBuffer、Uint8Array 或 Buffer

发送二进制数据,如 ArrayBuffer、Uint8Array 或 Node.js Buffer 对象。

content-length 头会被自动设置。

#Blob

发送 Blob 作为流。

Content-type 和 Content-Length 头会被自动设置。

#File

发送 File 作为流。

Content-type、Content-Length 和 Content-Disposition 头会被自动设置。

#特殊类型

以下是响应类型中一些不太常见的可能值。

#null 或 undefined

发送一个空响应体。

Tip

如果事件处理器中没有使用 return 语句,效果等同于 return undefined。

#Error

返回一个 Error 实例时,将发送此错误。

Important

建议 throw 异常而非直接返回错误实例,这样可以在任何嵌套工具中正确传播。

Read more in 错误处理.

#BigInt

会将 BigInt 类型值转换为字符串后发送。

Note

返回 JSON 对象时不支持 BigInt 序列化,你需要自己实现 .toJSON。详情可参考 MDN 文档。

#Symbol 或 Function

返回 Symbol 或 Function 的行为不可确定。 当前 H3 会发送类似字符串的未知 Symbol 和 Function 表示,但未来版本可能会改为抛出错误。

以下是 H3 内部已知的部分 Symbol:

  • Symbol.for("h3.notFound"):表示未找到路由,将抛出 404 错误。
  • Symbol.for("h3.handled"):表示请求已被某种方式处理,H3 不再继续(仅 Node.js 环境)。