SvelteKit 端点新特性:在 `+server.js` 中导出 `QUERY` HTTP 方法
2026/9/20 20:51:40 网站建设 项目流程
  • Web框架
  • 后端
  • 前端

【免费下载链接】kit

web development, streamlined

项目地址:https://gitcode.com/gh_mirrors/kit/kit
点击查看免费下载

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`

它声明了两件事:

  1. 影响范围@sveltejs/kit包的minor(次版本)级功能新增,而非破坏性变更;
  2. 特性内容+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_METHODSGET/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;urlparamslocals等照常可用;
  • 返回值必须是Response对象,可以借助@sveltejs/kit提供的textjson等辅助函数,也可以返回ReadableStream实现流式响应;
  • 可以使用errorredirect便捷方法;
  • 若请求方法在端点中没有对应导出(例如只导出了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 exportingPOST/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); } // ... }

由此可以梳理出三个行为规则:

  1. 直接按方法名取处理器mod[method],即QUERY请求会查找mod.QUERY
  2. HEAD的特殊退化:当请求为HEAD且端点未导出HEAD时,回退使用GET处理器(QUERY不受此逻辑影响);
  3. 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; } // ... }

由于QUERYENDPOINT_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

也就是说,QUERYPUTPATCHDELETEOPTIONS一样,是"页面不适用的方法",不存在歧义分支;而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 等构建逻辑,QUERYPOST等请求体依赖方法都不会被爬虫预取)。

这与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.jsQUERY方法的支持,为 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

项目地址:https://gitcode.com/gh_mirrors/kit/kit
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询