首页
/ 在 Next.js 中读写与删除 Cookie:with-cookies-next 示例的前端 / SSR / API 三端实战解析

在 Next.js 中读写与删除 Cookie:with-cookies-next 示例的前端 / SSR / API 三端实战解析

2026-09-06 18:32:07作者:袁立春Spencer

导读

examples/with-cookies-next 是 Next.js 仓库中一个高度聚焦的入门示例:它演示了如何借助 cookies-next 这个轻量库,在同一套 API 约定下完成 Cookie 的获取(get)、设置(set)与删除(remove),并且同时覆盖三种运行场景——浏览器端任意组件、getServerSideProps 服务端渲染流程、以及 API Route 处理器。读完本指南,你将掌握 cookies-next 在各场景下的完整调用形态与 { req, res } 选项约定,能直接在自己的 Next.js 项目里照搬这套"一套函数、三端通用"的 Cookie 管理方案。

该示例由一个 React 组件页面、一个 SSR 页面与三个 API Route 组成,全部使用 TypeScript,配套依赖仅需 cookies-next@^2.1.1,非常适合作为理解"客户端 Cookie 与 HTTP Cookie 头如何统一"的最小可运行样板。


一、示例整体结构:一屏看遍三种 Cookie 场景

先看清这个示例由哪些文件构成,方便后续对照:

examples/with-cookies-next/
├── package.json          # 依赖与 dev/build/start 脚本
├── tsconfig.json         # TypeScript 编译配置
├── README.md             # 官方示例说明
└── pages/
    ├── index.tsx         # 客户端场景:按钮驱动的 Cookie CRUD
    ├── ssr-cookies.tsx   # SSR 场景:getServerSideProps 中读写
    └── api/
        ├── set-api-cookie.ts    # API 场景:写入 Cookie
        ├── get-api-cookie.ts    # API 场景:读取 Cookie
        └── remove-api-cookie.ts # API 场景:删除 Cookie

从目录布局即可看出官方想传达的核心信息(README 原文概括为三条):

  • 可以在客户端任意位置使用——组件内直接调用,无需服务端上下文;
  • 可以在 getServerSideProps 中用于服务端渲染——响应前同步写入/读取;
  • 可以在 API 处理器中使用——面向接口的 Cookie 操作。

也就是说,cookies-next 的价值不在于"换一种 Cookie 写法",而在于把三个原本 API 风格各异的场景统一成同一套函数签名:在浏览器里不传选项直接调用;在 Node 端把 req/res 作为 { req, res } 传入即可。


二、快速开始:用 create-next-app 初始化示例

示例作者明确推荐通过 create-next-app 直接引导出项目骨架,三种主流包管理器均受支持:

npx create-next-app --example with-cookies-next with-cookies-next-app
yarn create next-app --example with-cookies-next with-cookies-next-app
pnpm create next-app --example with-cookies-next with-cookies-next-app

命令会以本仓库中的 with-cookies-next 目录为模板生成一个名为 with-cookies-next-app 的独立应用。生成后进入目录安装依赖并启动开发服务即可:

cd with-cookies-next-app
npm install        # 或 yarn / pnpm install
npm run dev        # 默认监听 http://localhost:3000

示例的 package.json 展示了完整的最小依赖集:

{
  "private": true,
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "cookies-next": "^2.1.1",
    "next": "latest",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@types/node": "^18.0.0",
    "@types/react": "^18.0.14",
    "typescript": "^4.7.4"
  }
}

几点值得注意:

  • 业务依赖只有 cookies-next 一个,Cookie 能力完全由它承载,Next.js 本体无需任何额外配置;
  • 项目启用 TypeScript(含 @types/node@types/react),tsconfig.json 使用 "jsx": "react-jsx"strict: false 等宽松但不失规范的默认项;
  • 提供标准三段式脚本 dev / build / start,可本地开发后构建部署。

该示例还内置了"一键部署到 Vercel 云平台"的 Deploy 入口,适合快速把演示应用发布上线体验效果。


三、客户端场景:在浏览器组件里操作 Cookie

客户端用法是整个示例的入口。打开首页后,页面渲染了五个按钮,分别绑定五个 cookies-next API。先看 pages/index.tsx 的完整实现:

import React from "react";
import {
  setCookie,
  getCookies,
  getCookie,
  deleteCookie,
  hasCookie,
} from "cookies-next";

const Home = () => {
  const handleSetCookie = () => setCookie("client-cookie", "mock client value");
  const handleCheckCookie = () => console.log(hasCookie("client-cookie"));
  const handleGetCookie = () => console.log(getCookie("client-cookie"));
  const handleGetCookies = () => console.log(getCookies());
  const handleDeleteCookies = () => deleteCookie("client-cookie");

  return (
    <div>
      <h1>Next Cookies</h1>

      <button onClick={handleSetCookie}>Set Cookie</button>
      <br />
      <button onClick={handleCheckCookie}>Check Cookie</button>
      <br />
      <button onClick={handleGetCookie}>Get Cookie</button>
      <br />
      <button onClick={handleGetCookies}>Get All Cookies</button>
      <br />
      <button onClick={handleDeleteCookies}>Remove Cookies</button>
    </div>
  );
};

export default Home;

这里一共演示了五个命名导出,职责如下:

函数 示例调用 作用 返回
setCookie setCookie("client-cookie", "mock client value") 写入单个 Cookie
hasCookie hasCookie("client-cookie") 判断指定 Cookie 是否存在 boolean
getCookie getCookie("client-cookie") 读取单个 Cookie 的值 值或 undefined
getCookies getCookies() 读取当前全部 Cookie 键值对象
deleteCookie deleteCookie("client-cookie") 删除指定 Cookie

要点说明:

  1. 客户端调用不需要传 req/res。此时函数内部直接操作浏览器的 document.cookie,与纯前端代码无差别,因此可以在任何组件、事件回调、Hook 或工具函数中自由使用。
  2. 结果是可观测的:示例把 hasCookie / getCookie / getCookies 的结果打到 console,配合浏览器 DevTools 的 Application → Cookies 面板,可以直观核对"点击 Set Cookie 后出现 client-cookie、点击 Remove Cookies 后消失"。
  3. 读取与写入形态解耦hasCookiegetCookiegetCookies 都只在发起 HTTP 请求时回读,是典型的"检查再读取"组合,适合做条件渲染或表单默认值回填。

四、SSR 场景:在 getServerSideProps 中读写 Cookie

客户端 API 只能影响当前浏览器。当需要在页面首屏渲染前决定 Cookie 的读取结果(例如登录态判断),就必须走服务端。示例用 pages/ssr-cookies.tsx 演示了在 Pages Router 的 getServerSideProps 中操作 Cookie:

import React from "react";
import { getCookies, getCookie, setCookies, removeCookies } from "cookies-next";

const SsrCookies = () => {
  return <div>SSR Cookies</div>;
};

export const getServerSideProps = ({ req, res }) => {
  setCookies("ssr-cookie", "mock-ssr-value", { req, res, maxAge: 60 * 6 * 24 });
  getCookie("client-cookie", { req, res });
  getCookies({ req, res });
  removeCookies("client-cookie", { req, res });
  return { props: {} };
};

export default SsrCookies;

这段代码信息量很大,逐条拆解:

  1. 多了一个 { req, res } 选项——这是 cookies-next 在服务端运行的"环境开关"。只要传入该选项,函数就会从 HTTP 层读取与写入,而不是操作 document.cookie
  2. setCookies("ssr-cookie", "mock-ssr-value", { req, res, maxAge: 60 * 6 * 24 }) 在 SSR 阶段向响应注入 Set-Cookie 头。maxAge 单位为60 * 6 * 24 即 8640 秒(约 2.4 天),该 Cookie 会随首屏 HTML 响应一起下发并被浏览器持久化。
  3. 读取与删除同样以 { req, res } 为基础getCookie("client-cookie", { req, res }) 读取的是请求携带的 Cookie(上一节在首页写入的 client-cookie 会出现在这里);removeCookies("client-cookie", { req, res }) 则通过设置过期时间为过去时刻来删除它。
  4. 组件本身 SsrCookies 只渲染一行文本,所有 Cookie 操作都发生在 getServerSideProps 中——这说明该库在服务端是同步、纯函数式的调用形态,逻辑上独立于 React 渲染层,数据通过 props 传给组件即可。

结合本仓库的 Pages Router 语义,getServerSideProps 每次请求都会在服务端执行,因此这里设置的 Set-Cookie 会被 Next.js 合并进最终响应头,天然满足"首次请求即种下 Cookie"的服务端场景需求。

补充:示例中同时出现了 setCookiessetCookieremoveCookiesdeleteCookie 两组命名。从页面代码分布看,它们是该库为不同书写习惯提供的等价 API(如首页用 setCookie/deleteCookie,SSR 页用 setCookies/removeCookies),实际使用时可统一风格,避免混用。


五、API 场景:在 Route Handler 中管理 Cookie

第三块拼图是 API Route。该目录下三个文件分别对应"写入 / 读取 / 删除",并且统一采用 try/catch 包裹、出错时返回 400 与错误信息的稳健写法。逐一来看:

5.1 写入 Cookie —— pages/api/set-api-cookie.ts

import { setCookie } from "cookies-next";

export default async function setApiCookie(req, res) {
  try {
    setCookie("api-cookie", "mock-value", { req, res, maxAge: 60 * 60 * 24 });
    res.status(200).send("set api cookies");
  } catch (error) {
    res.status(400).send(error.message);
  }
}

maxAge: 60 * 60 * 24api-cookie 的生命周期设为 86400 秒(1 天)。客户端只要请求该端点,就会在响应中收到 Set-Cookie: api-cookie=mock-value; Max-Age=86400

5.2 读取 Cookie —— pages/api/get-api-cookie.ts

import { getCookie, getCookies } from "cookies-next";
import { NextApiRequest, NextApiResponse } from "next";

export default async function getApiCookie(
  req: NextApiRequest,
  res: NextApiResponse,
) {
  try {
    const currentCookie = getCookie("api-cookie", { req, res });
    const allCookies = getCookies({ req, res });

    console.log("currentCookie: ", currentCookie);
    console.log("allCookies: ", allCookies);
    res.status(200).send("get api cookies");
  } catch (error) {
    res.status(400).send(error.message);
  }
}

这一版显式标注了 req: NextApiRequestres: NextApiResponse 类型(来自 next),是在 API Route 中使用 cookies-next 的推荐类型写法getCookie("api-cookie", { req, res }) 读取单个 Cookie,getCookies({ req, res }) 读取请求携带的全部 Cookie,结果在服务端日志可见。

5.3 删除 Cookie —— pages/api/remove-api-cookie.ts

import { deleteCookie } from "cookies-next";

export default async function setApiCookie(req, res) {
  try {
    deleteCookie("api-cookie", { req, res });
    res.status(200).send("remove api cookies");
  } catch (error) {
    res.status(400).send(error.message);
  }
}

通过 deleteCookie("api-cookie", { req, res }) 在响应中下发删除指令(将 Cookie 的 Max-Age 置为过期)完成清除。

三个端点合起来,便构成一套完整的"接口版"Cookie 生命周期:GET/POST set-api-cookie 写入 → GET get-api-cookie 读取 → GET remove-api-cookie 删除。这与浏览器端五个按钮形成镜像,让你可以在同一应用中对比两种环境下 API 的异同。


六、三种场景的调用约定速查

把示例中的全部调用点汇总成一张对照表,可在实际开发时快速检索:

运行场景 代表文件 写入 读取单个 读取全部 删除 是否需 { req, res }
客户端(浏览器) pages/index.tsx setCookie getCookie getCookies deleteCookie
SSR(getServerSideProps pages/ssr-cookies.tsx setCookies getCookie getCookies removeCookies
API Route pages/api/*.ts setCookie getCookie getCookies deleteCookie

由此可以推断该库的设计哲学(结合示例代码的调用形态,而非源码内部实现):

  • 统一的函数家族setgetgetAllremove/has 等动词在浏览器与 Node 端完全一致,学习成本被压到最低;
  • 环境由选项驱动:传入 { req, res } 即进入 HTTP 上下文(读取请求头中的 Cookie、把写入结果附加到响应头),不传则回退到 document.cookie
  • maxAge 统一按秒计:示例中 8640 秒(约 2.4 小时级 SSR 演示)与 86400 秒(1 天级 API 演示)都是秒为单位,可直接按业务换算,不设置则默认为会话级 Cookie。

七、上手该方案时的注意事项

基于本示例代码,整理几条实操时最容易被忽略的边界:

  1. 服务端写入本质是写响应头setCookiesgetServerSideProps 中生效的前提是 Next.js 会把该阶段设置的响应头合入最终 HTML 响应;因此在纯客户端静态页面不使用 Pages Router 数据获取函数的地方,服务端写入没有意义,应走客户端 API。
  2. 读取"别人种下的 Cookie"依赖请求头。SSR/API 中 getCookie("client-cookie", { req, res }) 读到的是客户端后续请求自动携带的 Cookie——这要求写入端与读取端的域名、路径保持一致。
  3. TypeScript 项目记得为 API handler 标注类型。参考 get-api-cookie.tsNextApiRequest / NextApiResponse 的用法,可获得完整的参数提示与错误检查。
  4. 错误处理可复用示例的 try/catch 模式。三个 API 端点都捕获异常并回 400 + error.message,避免 Cookie 解析失败时抛出未处理异常导致 500。
  5. 安全性仍由开发者负责。示例只用于演示 API 形态,生产环境若存放会话标识或敏感信息,仍需自行配置 HttpOnlySecureSameSite 等属性(cookies-next 支持将 Cookie 选项透传)。

若想继续深入,可对照阅读仓库中其他 Pages Router 数据获取与 API Route 的示例(如 with-cookies-next 目录外的 examples/with-iron-session 等基于 Cookie 的会话方案),观察在真实业务中如何在此基础上叠加加密与校验逻辑。

登录后查看全文
热门项目推荐
相关项目推荐