首页 / Svelte 5 入门教程 / Hooks 与错误处理

Svelte 5 入门教程

Hooks 与错误处理

本教程共 50 篇 · 第 50 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

SvelteSvelteKitHooks错误处理redirect

50. Hooks 与错误处理

本节目标:掌握 SvelteKit 的 Hooks 系统(handle、handleFetch、handleError),学会自定义错误页面(+error.svelte)、重定向和兜底错误处理。

Hooks 是什么

Hooks 是应用级别的函数,SvelteKit 在特定事件发生时调用它们。三个 hooks 文件:

文件运行环境用途
src/hooks.server.js仅服务端处理请求、数据库初始化
src/hooks.client.js仅客户端客户端错误处理
Note

SvelteKit 2 没有统一的 hooks.js,服务端和客户端的 hooks 是分开的两个文件。

这些文件在应用启动时加载,适合做初始化工作。

handle:请求拦截

handle 在每次服务端收到请求时运行。你可以修改请求、添加响应头,甚至完全绕过 SvelteKit:

// src/hooks.server.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
	// 拦截特定路径
	if (event.url.pathname.startsWith('/custom')) {
		return new Response('自定义响应');
	}

	// 正常处理请求
	const response = await resolve(event);

	// 添加自定义响应头
	response.headers.set('x-custom-header', 'hello');

	return response;
}

resolve(event) 渲染路由并生成 Response。你可以在它之前修改请求,之后修改响应。

locals:传递请求数据

handle 中给 event.locals 赋值,load 函数和 actions 就能访问:

// src/hooks.server.js
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
	// 从 cookie 获取用户信息
	const sessionid = event.cookies.get('sessionid');
	event.locals.user = await getUser(sessionid);

	return resolve(event);
}
// src/routes/+layout.server.js
/** @type {import('./$types').LayoutServerLoad} */
export function load(event) {
	return {
		user: event.locals.user  // 来自 handle 的数据
	};
}

app.d.ts 中声明 Locals 类型:

declare global {
	namespace App {
		interface Locals {
			user: {
				name: string;
				email: string;
			} | null;
		}
	}
}

export {};
Tip

handle 是实现认证的常用位置。在 handle 中验证 cookie、设置 locals.user,后续 load 和 actions 都能拿到用户信息。

多个 handle 函数

sequence 串联多个 handle 函数:

import { sequence } from '@sveltejs/kit/hooks';

/** @type {import('@sveltejs/kit').Handle} */
async function auth({ event, resolve }) {
	event.locals.user = await getUser(event.cookies.get('sessionid'));
	return resolve(event);
}

/** @type {import('@sveltejs/kit').Handle} */
async function logging({ event, resolve }) {
	const response = await resolve(event);
	console.log(`${event.request.method} ${event.url.pathname}`);
	return response;
}

export const handle = sequence(auth, logging);

handleFetch:拦截 fetch

handleFetch 可以修改 load 函数中 fetch 的行为。比如 SSR 时把外部 API 请求改为内部地址:

/** @type {import('@sveltejs/kit').HandleFetch} */
export async function handleFetch({ request, fetch }) {
	if (request.url.startsWith('https://api.myapp.com/')) {
		// SSR 时直接访问内网地址
		request = new Request(
			request.url.replace('https://api.myapp.com/', 'http://localhost:9999/'),
			request
		);
	}

	return fetch(request);
}

handleError:错误上报

handleError 在未捕获的错误发生时调用。用于日志记录和错误上报:

// src/hooks.server.js
import * as Sentry from '@sentry/sveltekit';

/** @type {import('@sveltejs/kit').HandleServerError} */
export async function handleError({ error, event, status, message }) {
	const errorId = crypto.randomUUID();

	// 发送到 Sentry
	Sentry.captureException(error, {
		extra: { event, errorId, status }
	});

	// 返回给用户的错误对象(会变成 page.error)
	return {
		message: '服务器出错了',
		errorId
	};
}

客户端也有 handleError

// src/hooks.client.js
/** @type {import('@sveltejs/kit').HandleClientError} */
export async function handleError({ error, event, status, message }) {
	console.error(error);
	return { message: '客户端出错了' };
}
Note

handleError 只处理未预期的错误。用 error() 函数抛出的预期错误不会触发它。

预期错误 vs 未预期错误

SvelteKit 区分两种错误:

预期错误:用 @sveltejs/kiterror() 函数主动抛出:

import { error } from '@sveltejs/kit';

export async function load({ params }) {
	const post = await db.getPost(params.slug);

	if (!post) {
		error(404, {
			message: '文章不存在',
			code: 'NOT_FOUND'
		});
	}

	return { post };
}

error() 会抛出异常,SvelteKit 捕获后设置状态码并渲染 +error.svelte

未预期错误:代码中的 bug、异常等。消息被隐藏,用户只看到 { message: "Internal Error" }

+error.svelte:错误页面

每个路由目录可以放 +error.svelte 自定义错误页面:

<!-- src/routes/blog/[slug]/+error.svelte -->
<script>
	import { page } from '$app/state';
</script>

<h1>{page.status}</h1>
<p>{page.error.message}</p>

page 对象包含 status(HTTP 状态码)和 error(错误对象)。

错误页面会向上查找——/blog/[slug]/ 下没有就去 /blog/,再没有去 /

Note

+error.svelte 不会处理 handle+server.js 中的错误。这些错误返回 JSON 或 error.html 兜底页面。

redirect:重定向

load 函数或 actions 中用 redirect 跳转:

import { redirect } from '@sveltejs/kit';

export function load() {
	redirect(308, '/new-location');
}

常用状态码:

状态码含义
301永久重定向(GET)
302临时重定向(GET)
307临时重定向(保持方法)
308永久重定向(保持方法)
Tip

路由迁移时用 308 永久重定向。表单提交后跳转用 303(POST 后 GET)。

error.html:兜底错误页

+error.svelte 也出错,或错误发生在根布局之外,SvelteKit 用 error.html 兜底:

<!-- src/error.html -->
<!DOCTYPE html>
<html lang="zh">
	<head>
		<meta charset="utf-8" />
		<title>%sveltekit.error.message%</title>
	</head>
	<body>
		<h1>出错了</h1>
		<p>状态码: %sveltekit.status%</p>
		<p>消息: %sveltekit.error.message%</p>
	</body>
</html>

这个文件是纯 HTML,没有 Svelte 组件,用于最严重的错误场景。

自定义错误类型

App.Error 接口扩展错误对象的类型:

// src/app.d.ts
declare global {
	namespace App {
		interface Error {
			message: string;
			code: string;
			errorId: string;
		}
	}
}

export {};

这样 page.error 就有类型提示,+error.svelte 中可以安全地访问 page.error.code

Hooks 速查表

Hook文件触发时机用途
handlehooks.server.js每次请求认证、修改请求/响应
handleFetchhooks.server.jsload 中调用 fetch修改 fetch 目标
handleErrorhooks.server.js + hooks.client.js未捕获错误日志、错误上报
handleValidationErrorhooks.server.js远程函数参数校验失败自定义校验错误

本节回顾

  • handle 拦截每个请求,可以设置 event.locals 传递数据,用 sequence 串联多个
  • handleFetch 修改 load 中的 fetch 请求,SSR 时可改为内网地址
  • handleError 处理未预期错误,用于日志和错误上报(Sentry 等)
  • 预期错误用 error() 抛出,未预期错误由 handleError 捕获
  • +error.svelte 自定义错误页面,向上查找最近的错误边界
  • redirect() 做重定向,error.html 是最后的兜底页面
  • App.Error 接口扩展错误对象类型,App.Locals 声明请求局部数据类型
上一篇
环境变量与构建适配器
下一篇
已经是最后一篇啦