ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JMeter登录后接口返回401?一文搞懂身份凭证传递与排查技巧

JMeter登录后接口返回401?一文搞懂身份凭证传递与排查技巧 经常跑 JMeter 压测的朋友十有八九都撞上过这个场景脚本明明把登录请求跑通了响应里也拿到 token 了可一到后续业务请求就齐刷刷返回401 Unauthorized。更憋屈的是同一个流程在 Postman 里点得飞起偏偏在 JMeter 里就是不行。这问题我前前后后排查过很多次也帮团队里不少人解决过今天把思路和手法完整梳理一遍希望能让后来者少踩几个坑。先说结论JMeter 里登录后报 401百分之九十以上不是 JMeter 本身的问题而是请求上下文没有正确传递——说白了就是服务端不认识你了。具体原因五花八门但排查路径是固定的。这篇文章不仅会带你走完整个排查流程还会把背后的原理讲透顺便附上常见的坑和规避方案。不管你是刚接触 JMeter 的测试新人还是被权限问题折磨过几次的“老油条”这篇内容应该都能派上用场。1. 先搞明白 401 到底是什么1.1 HTTP 状态码里 401 的真实含义在 HTTP 协议里401 的官方定义是Unauthorized意思是“未认证”或“认证失败”。也就是说服务端收到了你的请求但在当前请求里找不到有效的身份凭证或者凭证已经过期、被篡改、不匹配。这里需要区分两个很容易混淆的状态码401 和 403。401 是“你是谁我不认识你。”——你压根没证明自己的身份。403 是“我知道你是谁但你没资格看这个。”——身份有效但权限不够。排查时如果看到的是 403那走的是另一条路比如角色权限配置、接口权限控制等。而 401 的问题几乎都出在身份凭证的传递和有效性上。1.2 身份凭证在 JMeter 里是怎么传递的市面上主流的接口认证方式无非三种Session-Cookie、Token最常见的是 JWT、以及 Basic Auth。它们在 JMeter 里对应的传参方式完全不同。Session-Cookie 模式登录后服务端会在响应头里返回一个Set-CookieJMeter 需要用HTTP Cookie 管理器来保存并自动携带 Cookie。这项用起来最省心只要加一个 Cookie 管理器基本能自动处理。Token 模式登录接口返回的是 JSON 或 XML 里的一个 token 字符串后续请求需要在请求头里带上Authorization: Bearer token或者在参数里带 token具体看后端怎么约定。这一步需要从登录响应里提取 token再动态塞到后续请求的 Header 里。Basic Auth 最简单请求头里直接塞Authorization: Basic base64(用户名:密码)通常在 JMeter 里用 HTTP Header Manager 预置即可。很多 401 问题的根源就是这三种方式没对应上。比如后端期望的是 Token但你的脚本里用的是 Cookie或者后端期望 Header 传参但你的 token 放在了 URL 参数里。所以排查的第一步永远是搞清楚接口的认证方式。2. 登录后 401 的高频原因与排查路径2.1 从现象倒推原因先看报错发生在哪一步遇到 401别急着改脚本。先看 JMeter 的“察看结果树”定位一下 401 是出现在登录请求本身还是出现在登录之后的业务请求上。这个定位直接把排查范围缩小了一半。如果登录请求本身就返回 401问题在登录凭证——用户名密码不对、加密规则没实现、登录接口本身就要求前置条件比如验证码、签名。如果登录成功200但后续业务请求 401那问题几乎可以锁定在身份凭证没有正确传递或服务端不认账。现实中第二种情况占了绝大多数。下面重点拆解这种情况。2.2 Token 提取失败最隐蔽的坑用正则表达式提取器或 JSON 提取器时常会遇到一个陷阱提取器写对了但 token 是空的。我之前接过一个项目登录接口返回的数据很复杂token 嵌套在好几层 JSON 里。同事写了个正则去匹配结果匹配到了别的字段硬是拿了个“假 token”塞进了 Header。服务端一验无法解析这个 token直接返回 401。这类问题从结果上看是 401但根子在提取器。排查方法很简单在提取器后面加一个 Debug Sampler或者直接在结果树里看“请求体/请求头”里的 token 值。如果 token 为空、显示为undefined、或者明显是别的内容那就是提取器表达式的问题。JSON 提取器优先用 JSONPath 表达式比如$.data.token比正则稳妥得多。正则的话注意贪婪匹配和换行符问题必要时开启单行模式。2.3 请求头没带上加一个 Header 管理器就能解决这是新手最容易犯的错误。登录接口返回了 token也提取成功了但后续请求的 HTTP Header 里根本没加Authorization字段。JMeter 不像浏览器不会自动帮你补全 Headers。你写了多少个 Header它就发送多少个。想让后续请求带上 token需要手动添加HTTP Header Manager并在里面写好Authorization: Bearer ${token}注意这里的${token}是 JMeter 变量引用。只要这个变量在当前线程组内有值请求就会用真实 token 替换。但这里也有个隐患变量作用域。如果你把登录请求放在线程组 A业务请求放在线程组 B那么 A 线程组里定义的变量B 线程组默认取不到。具体后面会详细讲跨线程组传值的方案。2.4 Cookie 没有自动管理Session 场景的经典问题Session 模式下登录后服务端把JSESSIONID或类似标识种在 Cookie 里。JMeter 虽然提供了 HTTP Cookie 管理器但它有个特点如果脚本中显式添加了 Cookie 管理器默认情况下它会启用如果在测试计划级别配置了线程组之间会共享 Cookie。但有时候你忘了加 Cookie 管理器或者加了但放在错误的位置就会导致后续请求带不上 Cookie于是 401。遇到 Session 模式的接口我建议在测试计划根部加一个 HTTP Cookie 管理器让它作用于所有线程组。另外一个细节如果你的请求里手动设置了CookieHeader可能会和 Cookie 管理器冲突建议去掉手动的让管理器统一处理。2.5 Token 过期或并发环境下的新 token 覆盖了旧 token性能测试中还有一个令人头疼的场景压测时多个线程并发登录token 变量被反复覆盖。默认情况下JMeter 的变量是线程独立的。每个线程有自己的变量副本。但如果你用了${__setProperty}函数或者跨线程组共享变量就容易出现线程 A 的 token 被线程 B 覆盖了于是线程 A 后续请求拿着 B 的 token 去访问A 的会话校验失败自然 401。方案一不要跨线程共享登录态每个线程独立登录、独立使用自己的 token。方案二如果一定要共享比如登录接口只允许跑一次用__setProperty设置为全局属性然后通过${__P(var)}读取。请注意全局属性是所有线程共享的后续请求必须只读不能再写。3. 完整实操从零搭建一个能正确携带身份凭证的 JMeter 脚本3.1 环境准备与前置检查在开始写脚本之前先确认三件事JMeter 版本不能太老。至少用 5.x 以上新版本对 HTTP/2、JSON 提取器等支持更完整。确认接口协议是 HTTP 还是 HTTPS如果是 HTTPS是否能正确处理证书必要时可在jmeter.properties里关闭证书校验但压测环境慎用。抓包确认正常请求的 Headers 长什么样。用浏览器开发者工具F12或抓包工具Charles、Fiddler看一次成功的业务请求确认身份凭证放在 Header 的哪个字段、什么格式。提示抓包这一步非常关键。很多时候你以为需要的是 Bearer Token实际上后端要的是自定义的X-Token头或者还需要额外的时间戳、签名参数。以实际流量为准别靠猜。3.2 脚本结构设计登录一次还是每个线程都登录设计脚本时先想清楚业务场景单用户压测手动登录一次拿着有效凭证去循环压测业务接口。适合验证功能、调试脚本。多用户压测每个线程独立注册/登录各自持有 token 并发压测。更接近真实场景也是 401 问题高发区。预置用户池提前登录 N 个用户把 token 存到 CSV 文件里压测时每个线程从文件里取一个。兼顾效率与真实性适合大量并发的场景。如果是调试脚本阶段我强烈建议先用“单用户压测”模式跑通流程再过渡到多用户。不然变量作用域、token 覆盖、并发冲突全搅在一起排查起来非常痛苦。3.3 用 JSON 提取器正确获取 Token登录接口返回 JSON 时JSON 提取器是最省事的选择。假设登录响应如下{ code: 0, message: success, data: { accessToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.xxxxx, expiresIn: 7200 } }在登录请求上右键添加后置处理器 - JSON 提取器配置如下变量名称access_tokenJSONPath 表达式$.data.accessToken默认值NOT_FOUND配置完成后添加一个 Debug Sampler查看变量值是否正确。确认 token 和抓包里看到的格式一致再继续后面的步骤。3.4 把 Token 注入 HTTP Header两种方式方式一静态 Header适合调试直接在业务请求下加 HTTP Header Manager写入Authorization: Bearer ${access_token}如果此时变量已经存在请求发送时就会自动替换。这种方式简单直接缺点是如果业务请求特别多每个请求都要配一个 Header Manager其实也可以放到线程组级别统一配置。方式二动态 Header适合复杂场景如果 token 可能在中途过期需要刷新或者在同一个线程组里请求存在多种认证方式建议用JSR223 预处理程序动态设置 Header。用 Groovy 写几行脚本import org.apache.jmeter.protocol.http.control.Header; def token vars.get(access_token); sampler.getHeaderManager().add(new Header(Authorization, Bearer token));这种方式灵活但需要提醒一下Groovy 脚本在 JMeter 5.x 已经是内置支持不需要额外装插件放心用。3.5 跨线程组共享 Token属性与 CSV 的双方案如果你的测试计划里有多个线程组例如“线程组 A 执行登录并获取 token线程组 B 执行业务压测”那你不能直接引用变量因为变量是线程级的。方案一属性传递在登录请求的 JSR223 后置处理器里写入props.put(access_token, vars.get(access_token));在业务线程组里读取def token props.get(access_token); vars.put(access_token, token);需要注意属性是全局的多线程执行时存在覆盖风险。这个方案适合“登录一次全体共用”的场景比如用 setUp 线程组专门做初始化。方案二CSV 文件传递用 CSV 文件做中间桥梁登录线程组把多个用户的 token 写入文件业务线程组用 CSV 数据集配置逐行读取。虽然稍显繁琐但每个线程拿到的 token 互不干扰适合正式压测。4. 高级场景录制脚本、加密参数与动态刷新4.1 JMeter 录制 HTTPS 脚本时遇到的 401 陷阱很多朋友喜欢用 JMeter 自带的 HTTP(S) 测试脚本录制器抓包生成脚本。录制本身能省不少事但生成的脚本常常会遇到 401 问题。原因是录制时 JMeter 是作为代理转发流量它不一定能正确保存动态的 token 或 Cookie 关联逻辑。我个人的经验是录制脚本只用来“了解请求长什么样”真正压测用的脚本一定要手动清理和优化。优先删除冗余请求比如静态资源、埋点请求然后把登录响应里的动态值提取出来再做参数关联。录制完直接拿去压测几乎必然踩坑。4.2 带加密参数的登录接口怎么处理有些系统登录接口不是简单的用户名密码而是带 MD5、RSA、AES 等加密参数。这类接口如果不处理登录本身就是 401。如果密码是 MD5JMeter 直接用函数${__digest(MD5,123456,,,true,)}如果密码是 RSA 加密逻辑会复杂一些。一般做法是在 JSR223 预处理程序里用 Groovy 调用项目提供的加密类需要把 jar 包放到lib/ext目录或者调用一个加密接口把加密后的结果填入参数。这个阶段最耗时间的地方往往不是功能实现而是不知道加密方式。最简单的确认方法还是抓包比对输入参数是明文还是密文是固定盐值还是动态盐值。多抓几个包动态盐值通常一眼就能看出来。4.3 Token 过期与自动刷新机制压测时间拉长之后经常会遇到一个情况前 10 分钟跑得好好的10 分钟后开始大量报 401。查一下发现 token 有效期只有 600 秒过期了。应对策略有几个压测时长控制在 token 有效期内简单粗暴。脚本里实现自动刷新判断响应体里出现 401 时重新请求登录接口刷新 token。这个过程最好用While 控制器或JSR223 断言配合实现。预置 token 池按有效期批量预生成 token配合定时器控制切换。自动刷新在 JMeter 里实现要小心线程并发问题多个线程同时发现 token 过期同时去刷新会在登录接口上产生瞬时尖峰还可能出现刷新接口限流。实际项目中我更倾向预置 token 池稳得多。5. 实际排查案例一个典型 401 的完整复盘5.1 案例背景之前做过一个电商系统的接口压测登录接口正常查询订单接口报 401。抓包确认登录返回的是一个 JWT后续请求需要放在Authorization: Bearer token里。逻辑很清晰但脚本就是报 401。5.2 排查过程实录第一步看结果树。Token 提取成功了Debug Sampler 里显示的 token 也完整。第二步看请求头。业务请求的 Header 居然没有Authorization字段。我明明加了 Header Manager为什么没带上检查后发现这个 Header Manager 是挂在“登录请求”下的子节点而业务请求在另一个线程组压根儿没有引用这个 Header Manager。把 Header Manager 移到业务请求所在的线程组下重新跑请求头带上了 token但依然 401。第三步再仔细看。这次发现 Authorization 的值是Bearer eyJ...看着没问题但有个细节token 后面粘着一个换行符这是从 JSON 提取器里带出来的。某些后端会严格校验 token 字符串尾部多一个空白字符直接验签失败。第四步处理。在 JSON 提取器里把默认值写成NOT_FOUND并在 BeanShell/JSR223 后置处理器里用trim()清理变量值。再次运行200问题解决。5.3 复盘总结这个案例里踩了两个坑一是作用域问题二是隐藏字符问题。作用域问题说到底是 JMeter 的结构设计问题——父子节点的配置并不自动向下传递给兄弟节点每个层级要看它挂在哪个节点下面。隐藏字符问题则提醒我们凡是外部的、动态的、经过解析器处理的值都要留个心眼去检查格式是否干净。排错时多看看变量的实际长度、前后字符往往能找到意想不到的线索。6. 常见 401 排查速查表与经验技巧6.1 一张表对照排查现象可能原因排查方式解决方案登录接口直接 401账号密码错误、加密未实现抓包对比登录参数检查加密逻辑调用加密函数登录 200但后续全部 401请求头没带 token / Cookie查看结果树请求头添加 HTTP Header ManagerToken 值为空或 undefined提取器表达式错误Debug Sampler 查看变量修正 JSONPath 或正则压测几十分钟后开始 401Token 过期对比时间点与有效期预置 token 池或自动刷新多线程并发后部分 401变量被覆盖/共享冲突检查变量作用域改为每线程独立登录请求头带了 token 仍然 401隐藏字符、token 格式不对检查变量长度与字符清理空白符重新提取录制脚本回放 401动态值未参数化对比录制的请求手动提取关联动态值Header 管理器位置不对作用域设置错误查看节点树结构将配置移到目标线程组级6.2 核心避坑技巧调试阶段建议常开Debug Sampler和察看结果树确认每个步骤的中间结果。被“看起来对了但实际不对”的变量坑过太多次了多打印一层准没错。JMeter 脚本里能用 JSON 提取器就不要用正则提取器能用 JSR223 Groovy 就不要用 BeanShell。BeanShell 在新版 JMeter 里性能和兼容性都一般Groovy 才是现在的主流。再一个容易忽略的检查 JMeter 日志。运行窗口的日志里有时会直接打印 HTTP 错误响应内容这些内容不一定显示在结果树里但对排查非常有帮助。6.3 一个提升效率的小技巧如果在排查过程中你怀疑某个 Header 或参数的传递有问题但不想每次都跑完整流程可以用一个最简单的方法验证在同一次测试里加两个 HTTP 请求一个手动填写写死的 token从抓包里复制一个使用变量引用。如果写死的能通、变量引用的不行问题百分百在提取或传递环节如果写死的都不通问题在后端或环境跟 JMeter 无关。这个对比测试能帮你快速切分问题域省下大量时间。7. 几点实战心得跑 JMeter 这些年从最开始遇到 401 就抓瞎到现在基本可以在几分钟内定位问题所在最大的体会是权限问题大多数不是“权限配置”问题而是“凭证传递”问题。在 JMeter 里你扮演的不是浏览器而是一个只会发送 HTTP 请求的客户端。浏览器会自动帮你管理 Cookie、自动带上各种 Header但 JMeter 不会。所以脚本里每一个 Header、每一个变量、每一个后置处理器都需要你自己搭好。如果你正在被 401 困扰我建议先停下来把抓包拿到的最真实请求、响应、Headers 逐行对比脚本里的设置把“客户端自动做的事”在 JMeter 里显式地补上基本就能解决了。这条路我走过很多遍每一步都踩得到坑但每一步也都能学到东西。希望这篇整理能让你少走几个弯路。
返回列表