Karate API携带csrftoken登录重复请求致授权失败问题排查
测试场景与代码
主特性文件login-with-cookie.feature内容如下:
Feature: 使用API登录 Scenario: 通过csrftoken登录 * call read('file:src/test/java/lib/accounts/login/get-middleware-token.feature') * print response * def csrfmiddlewaretoken = response.token * print csrfmiddlewaretokenOnly * call read('file:src/test/java/lib/accounts/login/login.feature') { token: '#(csrfmiddlewaretokenOnly)' }
get-middleware-token.feature内容:
Feature: 中间件令牌 Scenario: 获取csrfmiddlewaretoken Given url baseUrl + '/token/' When method GET Then status 200
login.feature内容:
Feature: 使用API登录 Scenario: 登录 Given url baseUrl + '/accounts/login/' And form field csrfmiddlewaretoken = token And form field login = user And form field password = password And form field next = '/' When method POST Then status 302
问题现象
执行测试时,Karate会发送两次登录API请求(推测首次未获取session_id),最终用户登录失败,返回未授权状态(大概率因第二次请求携带两个csrftoken导致),请求日志如下:
10:11:15.933 request: 1 > POST https://stage.pollyex.com/accounts/login/ 1 > Content-Type: application/x-www-form-urlencoded 1 > Cookie: csrftoken=<token1> 1 > Content-Length: 132 1 > Host: stage.pollyex.com 1 > Connection: Keep-Alive 1 > User-Agent: Apache-HttpClient/4.5.13 (Java/11.0.18) 1 > Accept-Encoding: gzip,deflate csrfmiddlewaretoken=<middlewaretoken>&login=user&password=password&next=%2F 10:11:16.207 request: 2 > POST https://stage.pollyex.com/accounts/login/ 2 > Content-Type: application/x-www-form-urlencoded 2 > Cookie: csrftoken=<token1> 2 > Cookie: csrftoken=<token2> messages=<messages>; sessionid=<session-id> 2 > Host: stage.pollyex.com 2 > Connection: Keep-Alive 2 > User-Agent: Apache-HttpClient/4.5.13 (Java/11.0.18) 1 > Accept-Encoding: gzip,deflate csrfmiddlewaretoken=<middlewaretoken>&login=user&password=password&next=%2F
相同请求逻辑在Cypress中可正常运行,需排查问题并给出解决思路。
解决思路
修正变量引用错误
主特性文件中定义了csrfmiddlewaretoken = response.token,但调用登录feature时误用了未定义的csrfmiddlewaretokenOnly,这会导致请求参数异常,触发Karate的自动重试。将token: '#(csrfmiddlewaretokenOnly)'修改为token: '#(csrfmiddlewaretoken)'。禁用自动重试机制
Karate默认对失败请求自动重试,可通过配置关闭:* configure retry = { count: 0 }或在登录请求的断言后添加
retry 0,避免因302跳转被误判为失败而发起二次请求。手动清理重复Cookie
获取/token/接口的Cookie后,手动移除旧的csrftoken,避免重复携带:* def cookies = karate.get('cookies') * remove cookies.csrftoken * karate.set('cookies', cookies)或者在登录请求前显式设置Cookie,覆盖原有值:
And cookie csrftoken = csrfmiddlewaretoken控制跳转行为
首次登录请求返回302时,Karate可能自动跟随跳转导致二次请求。可禁用自动跳转:* configure followRedirects = false之后手动处理会话状态,确保sessionid正确传递。
对齐Cypress的请求行为
对比Cypress的请求细节:确认Cypress是否仅携带单个csrftoken、是否禁用自动跳转,调整Karate配置与之一致,比如保持Cookie池的唯一性、关闭自动重试等。
内容的提问来源于stack exchange,提问作者IsabelleT

