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

Cypress E2E测试出现重复Cookie设置异常,求根因与解决办法

根因分析
  • Nginx Cookie配置不统一:服务器返回的Set-Cookie头中,Domain属性存在两种格式——env.app.domain.com和.env.app.domain.com,导致Cypress将其识别为两组独立的Cookie。原生浏览器可能会自动兼容这类差异,但Cypress对Cookie的Domain解析更严格,因此出现重复存储的情况。
  • Cypress与原生浏览器的Cookie处理差异:Cypress的Cookie管理机制对hostOnly属性的判断更敏感,当同名Cookie的Domain格式不同时,会分别存储。后续请求可能错误携带hostOnly: false的xsrftoken,导致认证失败。
  • cy.session的缓存特性限制:cy.session会缓存sessiontoken这类稳定的认证Cookie,但xsrftoken通常是一次性生成的,缓存的sessiontoken无法与新生成的xsrftoken匹配,进而导致会话失效。
规避方案

1. 修正Nginx的Set-Cookie配置

统一Cookie的Domain属性,消除格式差异:

  • 若需匹配所有子域名,设置Domain=.env.app.domain.com(带前置点)
  • 若仅当前域名有效,直接移除Domain属性,让浏览器自动设置hostOnly: true

示例Nginx配置片段:

location / {
    add_header Set-Cookie "xsrftoken=xxx; Path=/; Domain=.env.app.domain.com; HttpOnly; Secure";
    add_header Set-Cookie "sessiontoken=xxx; Path=/; Domain=.env.app.domain.com; HttpOnly; Secure";
}

2. 在Cypress中拦截修正Cookie

使用cy.intercept拦截响应,修改Set-Cookie头统一Domain格式:

cy.intercept('POST', '/login', (req) => {
  req.continue((res) => {
    const correctedCookies = res.headers['set-cookie']?.map(cookie => {
      return cookie.replace(/Domain=env\.app\.domain\.com/, 'Domain=.env.app.domain.com')
    })
    if (correctedCookies) res.headers['set-cookie'] = correctedCookies
  })
})

3. 清理重复Cookie

在cy.session的验证阶段或登录前,主动清理不符合要求的Cookie:

cy.session('login', () => {
  cy.visit('/login')
  // 执行登录操作
  cy.get('#username').type('test')
  cy.get('#password').type('123456')
  cy.get('#submit').click()
}, {
  validate: () => {
    cy.getCookies().then(cookies => {
      // 清理hostOnly为false的目标Cookie
      const invalidCookies = cookies.filter(c => 
        !c.hostOnly && (c.name === 'xsrftoken' || c.name === 'sessiontoken')
      )
      invalidCookies.forEach(c => cy.clearCookie(c.name, { domain: c.domain }))
    })
  }
})

4. 优化单测试用例的Cookie清理

封装自定义命令,避免重复编写清理逻辑:

// cypress/support/commands.js
Cypress.Commands.add('prepareLogin', () => {
  cy.clearAllCookies()
  cy.visit('/login')
})

// 测试用例中调用
it('登录后访问首页', () => {
  cy.prepareLogin()
  // 执行登录操作
  cy.get('#username').type('test')
  cy.get('#password').type('123456')
  cy.get('#submit').click()
  cy.url().should('include', '/dashboard')
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:55:15