ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

LoadRunner性能测试中的认证问题解决方案

LoadRunner性能测试中的认证问题解决方案

1. LoadRunner认证失败问题解析

当你在LoadRunner中遇到{"msg":"请求访问:/getInfo,认证失败,无法访问系统资源","code":401}这样的错误时,这通常表示你的脚本在执行过程中遇到了认证问题。401状态码在HTTP协议中代表"Unauthorized",即未经授权的访问。

1.1 401错误的常见原因

在性能测试场景中,401错误通常由以下几种情况导致:

  1. Token缺失或过期:现代Web应用普遍采用Token-based认证机制,如果你的脚本中没有正确获取或传递Token,就会触发401错误。

  2. 认证信息配置错误:在录制脚本时捕获的认证凭据可能已过期,或者在回放时没有正确更新。

  3. 会话超时:某些系统的会话有效期较短,在长时间的性能测试中可能导致会话过期。

  4. CORS(跨域)问题:虽然CORS问题通常会返回403状态码,但在某些配置下也可能表现为401错误。

  5. API密钥无效:如果目标系统使用API密钥进行认证,而你的脚本中配置的密钥不正确或已撤销。

2. LoadRunner脚本中的认证机制

2.1 Token-based认证处理

现代Web应用最常见的认证方式是JWT(JSON Web Token)或OAuth Token。在LoadRunner中处理这类认证需要以下步骤:

  1. 获取Token:通常通过登录接口获取
web_reg_save_param_ex( "ParamName=access_token", "LB=\"access_token\":\"", "RB=\"", SEARCH_FILTERS, LAST); web_submit_data("login", "Action=https://api.example.com/auth/login", "Method=POST", "EncType=application/json", "Body={\"username\":\"{username}\",\"password\":\"{password}\"}", LAST);
  1. 在后续请求中使用Token:
web_add_header("Authorization", "Bearer {access_token}"); web_custom_request("get_info", "URL=https://api.example.com/getInfo", "Method=GET", LAST);

2.2 基本认证(Basic Auth)处理

对于使用Basic Auth的系统,LoadRunner提供了专门的函数:

web_set_user("username", "password", "example.com:443");

或者在请求头中直接添加:

char auth[100]; lr_save_string(lr_eval_string("{username}:{password}"), "credentials"); web_convert_param("credentials", "ENCODING", "BASE64", LAST); web_add_header("Authorization", "Basic {credentials}");

3. 常见问题排查与解决方案

3.1 Token过期问题

症状:脚本刚开始运行正常,但一段时间后开始出现401错误。

解决方案:

  1. 在脚本中添加Token刷新逻辑
  2. 设置合理的Think Time模拟真实用户行为
  3. 检查服务器设置的Token过期时间,适当调整测试场景持续时间
// Token刷新示例 if (strstr(lr_eval_string("{response}"), "token_expired")) { web_reg_save_param_ex("ParamName=new_token", ...); web_submit_data("refresh_token", ...); lr_save_string(lr_eval_string("{new_token}"), "access_token"); }

3.2 认证信息未正确传递

症状:所有请求都返回401错误。

排查步骤:

  1. 检查是否在所有需要认证的请求前添加了认证头
  2. 使用LoadRunner的日志功能验证Token是否正确生成和传递
  3. 对比录制脚本和实际请求的差异
// 调试输出Token内容 lr_output_message("使用的Token是: %s", lr_eval_string("{access_token}"));

3.3 动态认证参数处理

很多系统会在登录时返回动态的CSRF Token或类似的防伪参数,这些也需要捕获并在后续请求中使用:

web_reg_save_param_ex("ParamName=csrf_token", "LB=<input type=\"hidden\" name=\"csrf_token\" value=\"", "RB=\"", LAST); web_submit_form("login", ITEMDATA, "Name=username", "Value={username}", ENDITEM, "Name=password", "Value={password}", ENDITEM, "Name=csrf_token", "Value={csrf_token}", ENDITEM, LAST);

4. 高级认证场景处理

4.1 OAuth 2.0流程实现

对于使用OAuth 2.0的系统,需要在脚本中实现完整的授权码流程:

  1. 获取授权码
  2. 用授权码交换访问令牌
  3. 使用访问令牌访问资源
  4. 必要时刷新令牌
// 获取授权码 web_add_auto_header("Referer", "{referer_url}"); web_url("authorize", "URL=https://auth.example.com/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope={scope}", "Resource=0", "RecContentType=text/html", LAST); // 从重定向URL中提取code web_reg_save_param_ex("ParamName=auth_code", "LB=code=", "RB=&", LAST); // 交换Token web_submit_data("get_token", "Action=https://auth.example.com/token", "Method=POST", "EncType=application/x-www-form-urlencoded", "Body=grant_type=authorization_code&code={auth_code}&redirect_uri={redirect_uri}&client_id={client_id}&client_secret={client_secret}", LAST);

4.2 证书认证处理

对于需要客户端证书的HTTPS服务,需要在运行时设置证书:

web_set_certificate_ex("CertFilePath=client.pem", "CertFormat=PEM", "KeyFilePath=key.pem", "Password=123456", LAST);

5. 性能测试中的认证优化

在长时间运行的性能测试场景中,认证处理需要考虑以下优化:

  1. Token缓存:避免每次迭代都重新获取Token
  2. 连接复用:保持HTTP连接活跃减少握手开销
  3. 合理的认证频率:根据业务场景设计认证频率
// 使用lr_user_data_point实现Token缓存 if (lr_user_data_get("cached_token") == NULL) { // 获取新Token get_new_token(); lr_user_data_put("cached_token", lr_eval_string("{access_token}")); } else { lr_save_string(lr_user_data_get("cached_token"), "access_token"); }

6. 调试技巧与工具

6.1 使用Fiddler辅助调试

  1. 配置LoadRunner使用Fiddler作为代理
web_set_proxy("localhost:8888");
  1. 在Fiddler中检查实际发送的请求和接收的响应
  2. 对比成功和失败的请求差异

6.2 LoadRunner日志分析

启用详细日志记录:

web_set_option("Log", "ALL", LAST);

在日志中搜索:

  • "HTTP/1.1 401"
  • "Authorization:"
  • "WWW-Authenticate:"

6.3 使用web_get_int_property检查状态码

web_url("api_call", "URL=http://example.com/api", LAST); int http_status = web_get_int_property(HTTP_INFO_RETURN_CODE); if (http_status == 401) { lr_error_message("认证失败,HTTP状态码: %d", http_status); // 处理认证失败逻辑 }

7. 最佳实践与经验分享

  1. 认证信息参数化:永远不要在脚本中硬编码用户名密码
lr_save_string(lr_eval_string("{vuser}_user"), "username");
  1. 错误处理:为认证失败添加专门的错误处理逻辑
  2. 环境隔离:确保测试环境与录制环境一致
  3. 定期维护:随着系统认证机制升级更新测试脚本

一个健壮的认证处理框架示例:

vuser_init() { // 初始化认证信息 if (do_authentication() != LR_PASS) { lr_exit(LR_EXIT_VUSER_FAIL, "初始化认证失败"); } return 0; } action() { // 主业务逻辑 if (call_protected_api() == 401) { // 尝试刷新Token if (refresh_token() != LR_PASS) { // 刷新失败,重新认证 if (do_authentication() != LR_PASS) { lr_exit(LR_EXIT_VUSER_FAIL, "重新认证失败"); } } // 重试原始请求 call_protected_api(); } return 0; } int do_authentication() { // 实现认证逻辑 // 返回LR_PASS或LR_FAIL } int refresh_token() { // 实现Token刷新逻辑 // 返回LR_PASS或LR_FAIL }

在实际项目中,认证问题往往是性能测试脚本中最常见的故障点之一。掌握这些认证处理技巧可以显著提高脚本的稳定性和可靠性。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进