Svelte:如何将命名动作返回的Bearer令牌存入localStorage?
解决方案:在SvelteKit中获取登录令牌并存入localStorage
针对你的需求,有两种实用方案,可根据你想要的页面行为选择:
方案一:保留传统表单提交(页面刷新),从动作返回值中存令牌
利用SvelteKit命名动作的返回值,在页面加载时读取并写入localStorage:
- 修改+page.server.js的命名动作,返回获取到的令牌:
export const actions = { login: async ({ request }) => { const formData = await request.formData(); const username = formData.get('username'); const password = formData.get('password'); // 调用外部Web API获取令牌(你的原有逻辑) const apiRes = await fetch('https://你的API地址/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); const authData = await apiRes.json(); // 返回令牌,同时可保留原有写Cookie的逻辑 return { success: true, token: authData.token }; } };
- 在+page.svelte中处理返回值,页面加载时检查动作返回的令牌并存入localStorage:
<script> import { page } from '$app/stores'; import { onMount } from 'svelte'; onMount(() => { // 读取动作提交后返回的form数据 const loginResult = $page.form; if (loginResult?.success && loginResult.token) { // 存入localStorage localStorage.setItem('auth_token', loginResult.token); // 重定向到首页或其他页面,避免刷新后重复存储 window.location.href = '/'; } }); </script> <form method="POST" action="?/login"> <input type="text" name="username" placeholder="用户名" required /> <input type="password" name="password" placeholder="密码" required /> <button type="submit">登录</button> </form>
方案二:改用API路由实现无刷新登录(推荐)
通过创建SvelteKit的API路由,前端用fetch调用(服务器端转发请求避免跨域),直接拿到令牌存入localStorage,体验更流畅:
- 创建API路由文件
src/routes/api/login/+server.js:
export async function POST({ request }) { const { username, password } = await request.json(); // 服务器端调用外部API,不受浏览器同源策略限制 const apiRes = await fetch('https://你的API地址/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); if (!apiRes.ok) { return new Response(JSON.stringify({ error: '登录失败' }), { status: 401 }); } const authData = await apiRes.json(); // 返回令牌,也可在此设置Cookie return new Response(JSON.stringify({ token: authData.token }), { headers: { 'Content-Type': 'application/json' } }); }
- 在+page.svelte中用fetch调用API:
<script> let username = ''; let password = ''; let errorMsg = ''; async function handleLogin(e) { e.preventDefault(); errorMsg = ''; try { const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); if (!res.ok) { const errData = await res.json(); errorMsg = errData.error || '登录失败'; return; } const { token } = await res.json(); localStorage.setItem('auth_token', token); // 登录成功后跳转 window.location.href = '/'; } catch (err) { errorMsg = '网络异常,请稍后重试'; } } </script> <form on:submit={handleLogin}> <input type="text" bind:value={username} placeholder="用户名" required /> <input type="password" bind:value={password} placeholder="密码" required /> <button type="submit">登录</button> {#if errorMsg} <p style="color: #dc2626;">{errorMsg}</p> {/if} </form>
关键说明
- 你之前前端fetch跨域是因为浏览器的同源策略,但服务器端(+page.server.js或+server.js)调用外部API不受此限制,所以两种方案都能解决跨域问题。
- 方案二更符合现代单页应用的体验,无页面刷新;方案一适合需要保留传统表单提交行为的场景。
内容的提问来源于stack exchange,提问作者Tester101
相关产品推荐
相关产品推荐

