SvelteKit 的错误处理
错误是软件开发中不可避免的一部分。SvelteKit 会根据错误发生的位置、错误种类以及传入请求的性质,以不同方式处理错误。
错误对象
每个错误在渲染前都会经过 handleError 钩子。这个钩子可以记录错误并对其进行定制。钩子的 kind 属性表示错误来源:应用自身('app')、SvelteKit('framework')、远程函数参数校验('validation'),或未知来源('unknown')。默认情况下,这些错误都表示为简单的 { status: number, message: string } 对象。
可以添加其他属性,例如 code 或用于跟踪的 id,如下方示例所示。使用 TypeScript 时,需要按照后文“类型安全”的说明重新定义 Error 类型。
应用错误
应用错误是应用代码使用从 @sveltejs/kit 导入的 error 函数抛出的错误。
src/routes/blog/[slug]/+page.server.js
import { error } from '@sveltejs/kit';
import * as db from '#lib/server/database.js';
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
const post = await db.getPost(params.slug);
if (!post) {
error(404, 'Not found');
}
return { post };
}
TypeScript 版本
import { error } from '@sveltejs/kit';
import * as db from '#lib/server/database.js';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params }) => {
const post = await db.getPost(params.slug);
if (!post) {
error(404, 'Not found');
}
return { post };
};
这会抛出一个由 SvelteKit 捕获的异常,使响应状态码变为404,并渲染 +error.svelte 组件。其中的 error 是一个包含给定 status 和 message 的 App.Error 对象。
在到达组件之前,错误会以 kind: 'app' 经过 handleError 钩子。由于该错误的结构由应用自行决定,可以认为它适合公开展示,钩子可以原样传递它。
src/routes/+error.svelte
<script>
let { error } = $props();
</script>
<h1>{error.message}</h1>
TypeScript 版本
<script lang="ts">
let { error } = $props();
</script>
<h1>{error.message}</h1>
需要时,可以向错误对象添加额外属性:
error(404, 'Not found', {
code: 'NOT_FOUND'
});
框架错误
一些错误由 SvelteKit 自身产生,例如:请求未匹配任何路由(404);向没有 actions 的页面发送 POST 请求(405);请求体超过大小限制(413),等等。
这些错误也会经过 handleError,其 kind 为 'framework'。收到的 error 是一个 { status, message } 对象;message 是对问题的简短且可安全展示的描述,例如 'Not Found',因此可以直接呈现给用户。
如果在 handleError 中记录错误,请记住404等框架错误是常见情况,通常应避免记录它们。
校验错误
使用无效数据调用远程函数时,就会发生校验错误。将这类错误传入 handleError 时,还会附带一个 issues 数组。详情参见处理校验错误。
未知错误
未知错误指处理请求过程中出现的其他异常。因为这些错误可能包含敏感信息,未知错误的消息与堆栈跟踪不会公开给用户。
默认情况下,未知错误会打印到控制台;生产环境中则写入服务器日志。向用户暴露的错误采用通用结构:
{ "status": 500, "message": "Internal Error" }
未知错误以 kind: 'unknown' 经过 handleError 钩子,因为 SvelteKit 不知道具体发生了什么。可以在这里加入自己的错误处理逻辑,例如将错误发送到报告服务,或返回一个自定义错误对象,作为 error 属性传入 +error.svelte。你收到的是原始抛出值;除非主动选择暴露,否则其中的内容不会被展示。
返回的内容会覆盖默认值。例如,可以根据抛出错误的类型决定响应的 HTTP 状态码:
src/hooks.server.js
// Assuming you have this ...
class NotFound extends Error {}
/** @type {import('@sveltejs/kit/hooks').HandleServerError} */
export function handleError({ kind, error, event }) {
if (kind === 'unknown') {
// ... you can do this
if (error instanceof NotFound) {
return {
status: 404,
message: 'Not found'
};
}
return { message: 'Something went wrong' };
}
// app and framework errors are already safe to expose
return error;
}
TypeScript 版本
import type { HandleServerError } from '@sveltejs/kit/hooks';
// Assuming you have this ...
class NotFound extends Error {}
export const handleError: HandleServerError = ({ kind, error, event }) => {
if (kind === 'unknown') {
// ... you can do this
if (error instanceof NotFound) {
return {
status: 404,
message: 'Not found'
};
}
return { message: 'Something went wrong' };
}
// app and framework errors are already safe to expose
return error;
};
错误边界
在 load 或渲染期间发生的错误,例如组件的 <script> 块或模板中的错误,会向上传播到最近的 +error.svelte 组件。要以更细的粒度处理错误,可以使用 <svelte:boundary>:
<svelte:boundary>
...
{#snippet failed(error: App.Error)}
<!-- error went through the `handleError` hook and is of type `App.Error` -->
{error.message}
{/snippet}
</svelte:boundary>
响应
如果错误发生在 handle 或 +server.js 请求处理器中,SvelteKit 会根据请求的 Accept 头,返回后备错误页面或错误对象的 JSON 表示。
添加 src/error.html 文件即可定制后备错误页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>%sveltekit.error.message%</title>
</head>
<body>
<h1>My custom error page</h1>
<p>Status: %sveltekit.status%</p>
<p>Message: %sveltekit.error.message%</p>
</body>
</html>
SvelteKit 会将 %sveltekit.status% 与 %sveltekit.error.message% 替换为对应的值。
如果错误发生在页面渲染期间的 load 函数中,SvelteKit 会渲染距离错误发生位置最近的 +error.svelte 组件。如果错误发生在 +layout(.server).js 的 load 函数中,组件树里最近的错误边界是该布局上层的 +error.svelte 文件,而不是与它同级的文件。
例外情况是错误发生在根级 +layout.js 或 +layout.server.js 中,因为根布局通常会包含 +error.svelte 组件。这种情况下,SvelteKit 使用后备错误页面。
类型安全
如果使用 TypeScript 并需要定制错误结构,可以在应用中声明 App.Error 接口。按照惯例,该声明放在 src/app.d.ts 中,也可以放在 TypeScript 能识别的其他位置:
declare global {
namespace App {
interface Error {
code: string;
id: string;
}
}
}
export {};
这个接口始终包含 status: number 与 message: string 属性。
延伸阅读
来源与许可
来源:SvelteKit 官方文档:Errors,版权归 SvelteKit 贡献者所有。本文翻译正文并调整排版;保留当前官方示例。文档构建用的隐藏类型检查前置内容与高亮标记不属于可复制的页面代码,已按原站显示方式处理;原始 Markdown 源码随交付包保存。本文所述为该链接当前文档,不应套用于旧版 API。
Copyright (c) 2020 these people
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.











暂无评论内容