You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jest与Supertest测试HttpOnly刷新令牌端点失败,是否可行?

问题:Jest+Supertest测试HttpOnly刷新令牌接口时,令牌值始终为undefined

同事认为HttpOnly Cookie无法被浏览器交互,没法做集成测试;但Discord有人说HttpOnly仅限制浏览器,Jest不受此约束。我做了测试验证:目标是将登录接口返回的HttpOnly刷新令牌传入刷新接口获取新令牌,预期接口能打印令牌,实际结果却是undefined。

技术栈:Jest、Supertest、Express服务器

集成测试代码

import request from "supertest";
const api = request(server);

// 测试用例内代码
const loginResponse = await api.post("/auth/email/login").send({ email: signupPayload.email });
// 登录请求已成功
const rt1 = loginResponse.headers["set-cookie"][0].split("=")[1].split(";")[0];
const x = loginResponse.headers["set-cookie"][0]; 
// 此处可正常打印刷新令牌Cookie及其值
const refreshResponse = await api.post("/auth/jwt/refresh").set("refreshToken", x).send({});

无论用rt1还是x调用.set("refreshToken", arg)都无效,控制器中令牌值始终为undefined。

控制器代码

// 设置刷新令牌的控制器方法
public async emailLogin(req: Request, res: Response) {
      // 省略部分逻辑
            const cookieOptions = {
                httpOnly: true,
                expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
            };
            res.cookie("refreshToken", newRefreshToken, cookieOptions);
            return res.status(200).json({ member, accessToken });
}

// 刷新令牌的控制器方法
public async refreshJwt(req: Request, res: Response) {
        try {
            const token = req.cookies.refreshToken;
            console.log(token, "refresh token"); // 此处值为undefined!
            // 省略剩余逻辑
        } catch (err) { 
            // 错误处理
        }
   }

补充信息

我能正常打印出刷新令牌Cookie的值:refreshToken=a511d8a55839ee6a7d6102b3c0a184a432de160a3bd0e8a2c679e5fed272f3cac87eb17cfbff5af3; Path=/; Expires=Thu, 29 Dec 2022 23:33:24 GMT; HttpOnly,看起来内容正常但请求依然失败。

请问我是不是被误导了?用Jest和Supertest测试带HttpOnly刷新令牌Cookie的后端到底可行吗?还是我的操作哪里错了?


解答

你的问题出在Cookie的发送方式不符合HTTP规范,和HttpOnly属性无关:

  1. Cookie不是通过自定义的refreshToken请求头传递,而是必须放在Cookie请求头中。你直接用.set("refreshToken", x)是把完整Cookie字符串放到了一个自定义头里,后端的req.cookies是解析Cookie头的内容,自然拿不到值。
  2. HttpOnly只是限制浏览器前端JS通过document.cookie访问Cookie,对HTTP请求本身没有限制——不管是浏览器还是Supertest,只要按规范发送Cookie头,后端就能正常接收,所以Discord的说法是对的,Jest完全可以测试这类接口。

正确的测试写法

直接把登录接口返回的set-cookie内容放到Cookie请求头中即可:

// 登录请求成功后
const cookies = loginResponse.headers["set-cookie"];
// 发送刷新请求时设置Cookie头
const refreshResponse = await api.post("/auth/jwt/refresh")
  .set("Cookie", cookies) // Supertest会自动处理Cookie数组格式
  .send({});

如果只需要传递refreshToken这一个Cookie,也可以单独筛选:

const refreshTokenCookie = loginResponse.headers["set-cookie"].find(cookie => cookie.startsWith("refreshToken="));
const refreshResponse = await api.post("/auth/jwt/refresh")
  .set("Cookie", refreshTokenCookie)
  .send({});

额外提示

从你的代码能看出Express应用使用了cookie-parser中间件,它会自动解析Cookie头的内容并挂载到req.cookies上,只要正确设置Cookie头,就能正常拿到req.cookies.refreshToken的值。

内容的提问来源于stack exchange,提问作者plutownium

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 03:31:12