SvelteKit客户端钩子不执行问题排查及路由保护方案咨询
我来帮你梳理下问题所在,再聊聊路由保护的方案选择:
一、客户端钩子不执行的原因及修复
1. 旧版通用hooks.ts已被弃用
你提到hooks.ts完全没被读取,这是因为新版SvelteKit已经把通用钩子拆分成了hooks.server.ts(服务端钩子)和hooks.client.ts(客户端钩子),原来的hooks.ts不再被框架识别。你需要把服务端相关逻辑移到hooks.server.ts,客户端逻辑留在hooks.client.ts。
2. 客户端钩子没有reroute这个方法
你写的reroute函数根本不是客户端钩子支持的钩子类型!目前SvelteKit客户端钩子只支持handle、handleError这几个方法,reroute要么是旧版本的API,要么是服务端钩子才有的逻辑。想要在客户端拦截路由并重定向,得用handle钩子,示例代码如下:
// src/hooks.client.ts export async function handle({ event, resolve }) { console.log('Client handle hook triggered:', event.url); // 这里写你的路由判断逻辑 if (event.url.pathname !== '/hello') { // 重定向到/hello return new Response(null, { status: 302, headers: { Location: '/hello' } }); } // 正常处理请求 return resolve(event); }
替换成这个代码后,你应该能在浏览器控制台看到日志,并且路由会被重定向到/hello。
3. 模块加载但函数未执行的原因
你看到RUNNING: hooks.client.ts的日志,说明模块确实被加载了,但因为你导出的reroute不是客户端钩子的合法方法,所以框架根本不会调用它,换成handle就正常了。
二、路由保护:用钩子还是Layout?
你的疑问很合理,这两种方案各有适用场景,结合起来用效果最好:
1. 服务端钩子(推荐做权限验证)
既然你是对接Azure AD做认证,路由保护的核心逻辑一定要放在服务端钩子hooks.server.ts里。因为客户端代码可以被用户篡改,服务端验证才能确保真正的安全性——比如验证用户的Azure AD令牌是否有效、是否有权限访问当前路由。示例逻辑大概是这样:
// src/hooks.server.ts export async function handle({ event, resolve }) { // 从session或请求头里获取Azure AD的用户信息/令牌 const user = await event.locals.getSession(); // 如果未登录且访问的是需要授权的路由 if (!user && event.url.pathname.startsWith('/dashboard')) { return new Response(null, { status: 302, headers: { Location: '/login' } }); } return resolve(event); }
2. Layout组件(适合客户端UI处理)
Layout组件适合做客户端的友好提示,比如在未登录时显示登录按钮、隐藏页面内容,或者做客户端的路由跳转(但这只能作为补充,不能替代服务端验证)。比如在根+layout.svelte里:
<script> import { page } from '$app/stores'; import { getSession } from '$lib/auth'; // 你的认证逻辑 let user; async function checkAuth() { user = await getSession(); if (!user && $page.url.pathname.startsWith('/dashboard')) { window.location.href = '/login'; } } checkAuth(); </script> {#if user} <nav>欢迎,{user.name}</nav> {:else} <nav><a href="/login">登录</a></nav> {/if} <slot />
总结下:服务端钩子做安全拦截,Layout做用户体验优化,两者搭配是最佳实践。
备注:内容来源于stack exchange,提问作者Jason

