- Web框架
- 后端
- 前端
【免费下载链接】kit
web development, streamlined
SvelteKit 在本仓库当前代码中引入了一个新的端点能力:+server.js文件可以导出QUERY函数,用于处理QUERYHTTP 方法。本文以.changeset/pre/query-method-server-export.md记录的minor变更(feat: support the QUERY HTTP method in +server.js)为核心,结合源码、类型定义、官方路由文档与真实测试用例,讲解如何在项目中启用QUERY处理器、它的底层分发逻辑、与预渲染(prerender)的兼容性约束,以及它与页面路由、内容协商之间的边界规则。读完本文,你将能安全地在 API 端点中使用QUERY方法,并理解 SvelteKit 对它的一切处理细节。
这个变更记录了什么
.changeset/pre/query-method-server-export.md是仓库中标准的 changeset 变更描述文件,其内容如下:
--- "@sveltejs/kit": minor --- feat: support the `QUERY` HTTP method in `+server.js`它声明了两件事:
- 影响范围:
@sveltejs/kit包的minor(次版本)级功能新增,而非破坏性变更; - 特性内容:
+server.js端点现在支持导出QUERY处理器。
在该分支的代码中,这一特性已经完整落地:方法枚举、类型定义、运行时分发、文档与测试均已同步更新(详见下文各节)。对于使用 API 端点且需要"携带请求体的安全查询"场景(即请求参数放在 body 中、而非塞进 URL 的GET请求),QUERY是一个语义更合适的 HTTP 方法。
QUERY 是什么:一种"带请求体的查询"方法
从仓库的类型定义可以确认QUERY已被正式纳入 SvelteKit 认可的方法集合。在 types/private.d.ts 中:
export type HttpMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'QUERY';结合常量定义可以进一步理解它的语义定位。在 constants.js 中:
export const ENDPOINT_METHODS = [ 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD', 'QUERY' ]; export const MUTATIVE_METHODS = ['POST', 'PUT', 'PATCH', 'DELETE']; /** methods whose responses depend on the request body, so they can never be prerendered */ export const BODY_DEPENDENT_METHODS = [...MUTATIVE_METHODS, 'QUERY']; export const PAGE_METHODS = ['GET', 'POST', 'HEAD'];关键信息有三点:
QUERY被列入ENDPOINT_METHODS,即它是端点(+server.js)可导出的合法方法之一;- 它被归入
BODY_DEPENDENT_METHODS——源码注释明确写道"响应依赖请求体的方法,因此永远不能被预渲染"; - 它不在
PAGE_METHODS(GET/POST/HEAD)之列,说明QUERY只属于 API 端点,与页面渲染无关。
仓库中的真实测试用例也印证了"QUERY 携带请求体"这一行为。见 endpoint-output/query/+server.js:
import { text } from '@sveltejs/kit'; export function GET() { return text('get'); } /** @type {import('./$types').RequestHandler} */ export async function QUERY({ request }) { return text(`query: ${await request.text()}`); }该处理器通过await request.text()读取请求体并回显,验证了QUERY请求允许且应当携带 body。这与GET形成互补:当查询参数复杂、内容较长(例如结构化过滤条件)时,不再需要把它们编码进 URL。
如何编写一个处理 QUERY 方法的端点
与其它端点方法完全一致,你只需要在src/routes/.../+server.js中按方法名导出异步函数:
/// file: src/routes/api/search/+server.js import { json } from '@sveltejs/kit'; /** @type {import('./$types').RequestHandler} */ export async function QUERY({ request, url }) { // 从请求体中读取结构化查询条件 const body = await request.json(); // ...执行查询逻辑... return json({ results, matched: body.filters.length }); }要点归纳:
- 处理器接收标准的
RequestEvent,其中request是原生Request对象,可读取 body;url、params、locals等照常可用; - 返回值必须是
Response对象,可以借助@sveltejs/kit提供的text、json等辅助函数,也可以返回ReadableStream实现流式响应; - 可以使用
error与redirect便捷方法; - 若请求方法在端点中没有对应导出(例如只导出了
QUERY却收到了PUT请求),SvelteKit 会返回 405,并在Allow响应头中列出实际支持的方法(见下文"运行时分发"一节)。
官方路由文档同样把QUERY列为端点可导出的方法集合。见 10-routing.md 与 10-routing.md:
Your
+server.jsfile exports functions corresponding to HTTP verbs likeGET,POST,PATCH,PUT,DELETE,OPTIONS,HEAD, andQUERY...By exporting
POST/PUT/PATCH/DELETE/OPTIONS/HEAD/QUERYhandlers,+server.jsfiles can be used to create a complete API.
运行时是如何分发 QUERY 请求的
端点请求的统一入口是 runtime/server/endpoint.js 中的render_endpoint。它根据请求方法取出对应的导出函数:
export async function render_endpoint(event, state, mod) { const method = /** @type {import('types').HttpMethod} */ (event.request.method); let handler = mod[method] || mod.fallback; if (method === 'HEAD' && !mod.HEAD && mod.GET) { handler = mod.GET; } if (!handler) { return method_not_allowed(mod, method); } // ... }由此可以梳理出三个行为规则:
- 直接按方法名取处理器:
mod[method],即QUERY请求会查找mod.QUERY; HEAD的特殊退化:当请求为HEAD且端点未导出HEAD时,回退使用GET处理器(QUERY不受此逻辑影响);- 405 兜底:找不到对应处理器时调用
method_not_allowed。
method_not_allowed实现在 runtime/server/utils.js,它返回 405 状态码,并通过allowed_methods生成符合 HTTP 规范的Allow响应头:
export function method_not_allowed(mod, method) { return text(`${method} method not allowed`, { status: 405, headers: { allow: allowed_methods(mod).join(', ') } }); } /** @param {Partial<Record<import('types').HttpMethod, any>>} mod */ export function allowed_methods(mod) { const allowed = ENDPOINT_METHODS.filter((method) => method in mod); // if there's no HEAD handler, but we have a GET handler, we respond to // HEAD requests using the GET handler and omit the response body. if ('GET' in mod && !('HEAD' in mod)) { allowed.push('HEAD'); } return allowed; }注意allowed_methods遍历的是ENDPOINT_METHODS(已包含QUERY),因此导出了QUERY的端点在收到不支持的方法时,Allow头会正确列出QUERY。
QUERY 请求永远交给端点处理:内容协商规则
同一路由下可以同时存在+page与+server.js,此时 SvelteKit 需要判定一个请求是页面请求还是 API 请求。判定函数is_endpoint_request同样位于 runtime/server/endpoint.js:
export function is_endpoint_request(event) { const { method, headers } = event.request; // These methods exist exclusively for endpoints if (ENDPOINT_METHODS.includes(method) && !PAGE_METHODS.includes(method)) { return true; } // ... }由于QUERY在ENDPOINT_METHODS中却不在PAGE_METHODS中,任何QUERY请求都会被无条件判定为端点请求,直接交给+server.js处理,绝不会被当成页面请求。官方文档 10-routing.md 的"内容协商"一节对此有明确表述:
PUT/PATCH/DELETE/OPTIONS/QUERYrequests are always handled by+server.jssince they do not apply to pages
也就是说,QUERY与PUT、PATCH、DELETE、OPTIONS一样,是"页面不适用的方法",不存在歧义分支;而GET/POST/HEAD则需依据Accept头是否优先text/html来判断是页面还是端点。
与预渲染(prerender)的兼容性约束
QUERY方法的响应依赖请求体,因此它被划入BODY_DEPENDENT_METHODS。这一划分直接作用于预渲染流程:在 runtime/server/endpoint.js 中,如果端点开启了prerender,同时又存在请求体依赖方法或fallback处理器,则直接抛错:
const prerender = mod.prerender ?? state.prerender_default; if ( prerender && (mod.fallback || /** @type {import('types').HttpMethod[]} */ (BODY_DEPENDENT_METHODS).some( (method) => mod[method] )) ) { throw new Error('Cannot prerender endpoints with body-dependent methods or fallback handlers'); }实操建议:
- 若
+server.js导出了QUERY,请不要对该路由声明export const prerender = true,否则构建(build)阶段会抛出上述错误; - 同理,若某个子路由在
+layout.js/+page.js中开启全局预渲染,涉及QUERY的端点也需要显式关闭预渲染或用fallback之外的方式规避(根据 postbuild/prerender.js 等构建逻辑,QUERY与POST等请求体依赖方法都不会被爬虫预取)。
这与POST等变更型方法的行为一致:凡是"响应依赖请求内容"的端点都不适合静态预渲染。
与 Remote Functions 中query的关系
值得一提的是,仓库中的另一套机制——remote functions($app/server导出的query/form/command/prerender四种远程函数)——在客户端会被转换成对生成端点的fetch调用,其中query类型的读取操作在服务端通过GET请求执行(见 runtime/server/remote-functions.js 中对query.live必须走GET的校验),而query.batch则要求POST。
也就是说:QUERY方法是"开发者手工编写+server.js端点"时可直接导出的 HTTP 方法;而 remote functions 的query是框架层的高级抽象,二者概念不同、底层请求方法也不同,但都服务于"从服务端读取数据"这一目标。如果你需要手写底层 API 并希望请求参数放在 body 中,QUERY方法就是为这种语义准备的。
小结
+server.js对QUERY方法的支持,为 SvelteKit 端点补充了"带请求体、语义为查询"的 HTTP 能力。需要记住的关键事实如下:
| 事实 | 证据 |
|---|---|
QUERY是合法的端点导出方法 | constants.js 的ENDPOINT_METHODS |
QUERY属于请求体依赖方法,不可预渲染 | constants.js 与 endpoint.js 的构建期校验 |
QUERY请求总是由+server.js处理,不参与页面协商 | endpoint.js 与 10-routing.md |
HttpMethod类型已包含'QUERY' | types/private.d.ts |
| 官方有可直接运行的示例 | endpoint-output/query/+server.js |
在实战中使用时,只需在+server.js中导出QUERY({ request })即可,注意不要对该路由开启预渲染,其余行为(405 兜底、Allow头生成、流式响应、错误处理)都与其它端点方法完全一致。
- Web框架
- 后端
- 前端
【免费下载链接】kit
web development, streamlined
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考