HTTP QUERY 方法
接受在请求体中携带查询内容的安全、可缓存请求。
HTTP QUERY 方法(RFC 10008)类似于 GET —— 安全、幂等且可缓存 —— 但会在请求 体 中通过 Content-Type 携带查询内容。它是对“我需要使用 GET,但我的查询内容对于 URL 来说过大或结构过于复杂”这一需求的标准解决方案。
H3 通过 app.query() 将 QUERY 作为一等方法提供,并额外提供两个辅助工具。
注册 QUERY 处理器
读取请求体的方式与处理 POST 一样:
import { readBody } from "h3";
app.query("/books", async (event) => {
const query = await readBody(event, { type: "text" });
return runSearch(query);
});
由于 QUERY 携带可由攻击者控制的请求体,请求体大小限制与 POST 一样适用。
广告支持的格式
使用 appendAcceptQuery 告知客户端资源理解哪些查询格式。它会设置 Accept-Query 响应标头(一个 结构化字段 列表),也可以在普通的 GET 请求中设置,以便客户端在发送 QUERY 请求之前发现可用格式:
import { appendAcceptQuery } from "h3";
app.get("/books", (event) => {
appendAcceptQuery(event, ["application/sql", "application/jsonpath"]);
// Accept-Query: application/sql, application/jsonpath
return "Send a QUERY request with a SQL or JSONPath body.";
});
验证 Content-Type
使用 requireContentType 强制执行 RFC 的错误语义。它返回匹配的媒体类型,或抛出 400(缺失)、415(不支持)或 422(格式错误):
import { requireContentType, readBody } from "h3";
app.query("/books", async (event) => {
const type = requireContentType(event, ["application/sql", "application/jsonpath"]);
const query = await readBody(event, { type: "text" });
return runQuery(type, query);
});
提供可缓存的 GET 替代方案
QUERY 响应无法通过 URL 寻址,因此浏览器和 CDN 无法缓存它。RFC 10008 建议通过 Content-Location 标头将客户端指向一个等效且可缓存的 GET。使用稳定的 ID 保存结果,并让客户端通过普通的、可由 HTTP 缓存的 GET 重复查询:
app.query("/books", async (event) => {
const result = runQuery(type, query);
const id = queryId(type, query); // 查询的稳定哈希值
cache.set(id, result);
event.res.headers.set("content-location", `/books/${id}`);
return result;
});
完整示例
一个自包含、可运行的演示——一个 /books 资源,接受类似 SQL 和 JSONPath 的查询,验证 Content-Type,并提供一个可缓存的 GET 替代方案。同时,它还会在 / 提供一个小型交互页面。