为什么我在 NextJs 项目中使用 cookie 存储 token 而不是使用 localstorage

在构建现代 Web 应用时,身份验证(Authentication) 是几乎每个项目都需要处理的重要功能。当用户登录成功后,服务器通常会返回一个 Token(如 JWT),客户端需要将它保存下来,并在后续请求中用于验证身份。

常见的两种存储方式是:

  • localStorage:浏览器本地持久化存储,开发者最常用的方式之一

  • Cookie:浏览器内置的请求头机制,可配置多个安全策略

我在最开始使用 Next.js 构建项目时,和很多人一样优先选择了 localStorage。但随着对 Next.js(尤其是 App Router 架构)理解的加深,我逐渐发现:localStorage 根本不适合存 Token,最终我全面转向了 使用 Cookie 来存储身份凭证。

在接下来的内容当中,我们将从原理、安全、框架兼容性等角度全面剖析我的这个选择。

Next.js 项目的运行环境:不仅仅是浏览器

Next.js 是一个混合型应用框架,它不仅支持传统的客户端渲染(CSR),还广泛使用:

  • 服务端组件(Server Components)

  • 中间件(middleware.ts)

  • Edge Function(边缘运行环境)

  • API Routes / Server Actions

  • 静态生成(SSG)、服务端渲染(SSR)

这意味着你的项目运行环境不仅包括浏览器(客户端),还包含 Node.js、Edge Runtime 等 无浏览器 API 的环境。

为什么 localStorage 不适合 Next.js 项目?

虽然 localStorage 在前端框架中常被用于临时存储 token,但在 Next.js 项目中,它存在以下硬伤:

1. 无法在服务端访问

Next.js 的服务端组件(Server Component)、Server Action、Edge Function 中无法访问浏览器的 localStorage,因为它们运行在服务端或边缘节点,而 localStorage 是浏览器环境独有的 API。

tsx 复制代码
// app/profile/page.tsx - Server Component 中
export default function ProfilePage() {
  const token = localStorage.getItem("token"); // ❌ 报错:localStorage is not defined
}

2. 中间件中无法读取 localStorage

middleware.ts 是基于 Edge Runtime 执行的,也无法访问任何浏览器 API,包括 localStorage。如果你想基于 token 做权限路由控制,就完全不能依赖 localStorage。

ts 复制代码
// middleware.ts
export function middleware(request: NextRequest) {
  const token = localStorage.getItem("token"); // ❌ Edge 环境下不可能存在
}

3. 暴露在客户端,容易被 XSS 攻击

localStorage 是开放的,所有脚本都可以访问。一旦页面存在 XSS 漏洞,token 会直接被窃取,造成严重安全风险。

为什么我选择使用 Cookie?

相较于 localStorage,Cookie 是浏览器原生支持的机制,它在 Next.js 中具备更强的兼容性和安全性:

Next.js 提供了 cookies() API,可在 服务端组件、Server Action、API Route、Middleware 等多个环境中访问 Cookie。

tsx 复制代码
// app/dashboard/page.tsx
import { cookies } from "next/headers";

export default function DashboardPage() {
  const token = cookies().get("token")?.value;

  if (!token) {
    // 重定向或提示登录
  }

  return <div>欢迎回来!</div>;
}

浏览器会自动把 Cookie 附带到每次同源请求中:

  • 页面加载时自动发送给 SSR 服务
  • 请求 /api/xxx 时自动带上 Cookie
  • 服务端可以直接读取,不依赖前端注入

这让身份验证逻辑天然融合到请求流程中,不需要你手动设置任何请求头。

设置 HttpOnly 后,JavaScript 无法访问 Cookie,从而彻底解决 XSS 窃取 Token 的风险。

ts 复制代码
res.cookies.set("token", token, {
  httpOnly: true,
  secure: true,
  maxAge: 3600,
  path: "/",
});

中间件是页面加载前的"守门员",只支持 Cookie:

ts 复制代码
// middleware.ts
import { NextRequest, NextResponse } from "next/server";

export function middleware(request: NextRequest) {
  const token = request.cookies.get("token")?.value;

  if (!token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  return NextResponse.next();
}

你可以精准拦截未登录用户、限制特定路由访问权限。

举个例子:登录/登出流程(App Router)

接下来我们将使用一个登录/登出的例子来讲解一下 Cookie 在 NextJs项目中的应用。

ts 复制代码
// app/api/login/route.ts
import { NextResponse } from "next/server";

export async function POST(request: Request) {
  const body = await request.json();
  const token = await verifyUserAndGenerateToken(body);

  const response = NextResponse.json({ success: true });

  response.cookies.set("token", token, {
    httpOnly: true,
    path: "/",
    maxAge: 60 * 60 * 24,
  });

  return response;
}

服务端组件中读取 token

tsx 复制代码
// app/dashboard/page.tsx
import { cookies } from "next/headers";
import { redirect } from "next/navigation";

export default function DashboardPage() {
  const token = cookies().get("token")?.value;

  if (!token) {
    redirect("/login");
  }

  return <div>用户中心</div>;
}

middleware 权限拦截

ts 复制代码
// middleware.ts
import { NextRequest, NextResponse } from "next/server";

export function middleware(request: NextRequest) {
  const token = request.cookies.get("token")?.value;

  const isProtected = request.nextUrl.pathname.startsWith("/dashboard");
  if (isProtected && !token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  return NextResponse.next();
}
ts 复制代码
// app/api/logout/route.ts
import { NextResponse } from "next/server";

export async function POST() {
  const response = NextResponse.json({ success: true });

  response.cookies.set("token", "", {
    maxAge: 0,
    path: "/",
  });

  return response;
}

总结

在 App Router 架构下,Next.js 已不再是一个纯前端框架,而是一个真正的全栈应用平台。因此,Token 的存储方式也必须适应全栈环境的特性。

Cookie,作为浏览器与服务端之间天然的桥梁,是目前在 Next.js 项目中存储 Token 最合理、最安全、最兼容的方式。

如果你还在用 localStorage 存 token,是时候升级你的身份认证方案了。

功能/特性 Cookie ✅ localStorage ❌
SSR / RSC 可访问 cookies() 可用 ❌ 无法在服务端读取
middleware 可访问 request.cookies 可用 ❌ 不存在 localStorage
自动附加请求 ✅ 默认随请求发送 ❌ 需手动加到 headers
可设置 HttpOnly ✅ 防止 XSS ❌ 直接暴露给 JS
安全性 ✅ 高,可配置 Secure/SameSite ❌ 容易被 XSS 攻击
易用性(在 App Router) ✅ 与新架构天然兼容 ❌ 基本不可用
相关推荐
前端小巷子5 分钟前
跨域问题解决方案:开发代理
前端·javascript·面试
前端_逍遥生5 分钟前
Chrome 插件开发到发布完整指南:从零开始打造 TTS 朗读助手
前端·chrome
JohnYan5 分钟前
Bun技术评估 - 07 S3
javascript·后端·bun
Mintopia5 分钟前
Three.js 材质与灯光:一场像素级的光影华尔兹
前端·javascript·three.js
天涯学馆7 分钟前
JavaScript 跨域、事件循环、性能优化面试题解析教程
前端·javascript·面试
掘金一周15 分钟前
别再用 100vh 了!移动端视口高度的终极解决方案| 掘金一周7.3
前端·后端
晴殇i17 分钟前
CSS 迎来重大升级:Chrome 137 支持 if () 条件函数,样式逻辑从此更灵活
前端·css·面试
咚咚咚ddd19 分钟前
cursor mcp实践:网站落地页性能检测报告(browser-tools)
前端
MiyueFE20 分钟前
让我害怕的 TypeScript 类型 — — 直到我学会了这 3 条规则
前端·typescript
Hilaku20 分钟前
2025年,每个前端都应该了解的CSS选择器:`:has()`, `:is()`, `:where()`
前端·css