k6性能测试OAuth2令牌生成报错及复用需求求助
解决k6 OAuth2令牌生成错误及复用问题
错误原因分析
你遇到的TypeError: Cannot read property 'access_token' of undefined主要由以下几点导致:
- 全局响应体丢弃配置:
options里设置了discardResponseBodies: true,导致令牌请求的响应体被清空,JSON.parse(res.body)返回undefined,无法读取access_token。 - 缺少请求错误处理:未检查令牌请求的响应状态,若请求失败(如网络异常、认证参数错误),直接解析响应体必然报错。
- 变量名拼写错误:测试函数中使用
resp.timings.duration,但实际变量名是response,会导致额外的未定义错误。
修复方案及令牌复用实现
1. 修复令牌生成逻辑
- 禁用令牌请求的响应体丢弃(或全局关闭)
- 添加响应状态检查,确保请求成功后再解析
- 修正变量名错误
2. 实现令牌一次性生成复用
利用k6的setup()函数,该函数在测试开始前仅执行一次,生成的令牌可传递给所有VU的测试函数使用,避免重复请求令牌。
完整修正代码
import http from 'k6/http'; import { htmlReport } from 'https://raw.githubusercontent.com/benc-uk/k6-reporter/2.4.0/dist/bundle.js' import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.1/index.js' import { Trend } from 'k6/metrics'; import { sleep } from 'k6'; // 补充导入sleep export const options = { discardResponseBodies: true, // 全局保留该配置,在令牌请求中单独覆盖 scenarios: { getItems: { executor: 'constant-arrival-rate', exec: 'getItems', duration: '1m', rate: 1, preAllocatedVUs: 2, timeUnit: "1s", }, getItemsExport: { executor: 'constant-arrival-rate', exec: 'getItemsExport', duration: '1m', rate: 1, preAllocatedVUs: 2, timeUnit: "1s", }, postItemsSummary: { executor: 'constant-arrival-rate', exec: 'postItemsSummary', duration: '1m', rate: 1, preAllocatedVUs: 2, timeUnit: "1s", }, }, summaryTrendStats: ["min", "max", "avg","med", "p(90)", "p(95)","p(99)", "count"], }; let requestTrend1 = new Trend('Request1') let requestTrend2 = new Trend('Request2') let requestTrend3 = new Trend('Request3') // 修正重复的Trend名称 // 测试前一次性生成令牌 export function setup() { const clientId = ''; // 填入你的client_id const clientSecret = ''; // 填入你的client_secret const tokenUrl = 'https://token_creator.com/oauth2/token'; const body = `grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}`; // 单独禁用该请求的响应体丢弃 const res = http.post(tokenUrl, body, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, discardResponseBodies: false }); // 检查请求状态,失败则抛出错误终止测试 if (res.status !== 200) { throw new Error(`令牌请求失败,状态码:${res.status},响应内容:${res.body}`); } const result = JSON.parse(res.body); if (!result.access_token) { throw new Error('未从响应中获取到access_token'); } return { token: result.access_token }; } //get Items export function getItems(data) { console.log("Executing getItems ") const token = data.token; // 从setup返回的数据中获取令牌 const apiUrl = 'https://local.com/v1/items?site2'; const headers = { Authorization: `Bearer ${token}`, Connection: `keep-alive` }; const response = http.get(apiUrl, { headers }); console.log(`Response status: ${response.status}`); requestTrend1.add(response.timings.duration) // 修正变量名 sleep(1); } //get Items export export function getItemsExport(data) { const token = data.token; const apiUrl = 'https://local.com/v1/items/export?offset=0&limit=200&site=1'; const headers = { Authorization: `Bearer ${token}`, Connection: `keep-alive` }; const response = http.get(apiUrl, { headers }); console.log(`Response status: ${response.status}`); requestTrend2.add(response.timings.duration) // 修正变量名 sleep(1); } export function postItemsSummary(data) { console.log("Executing postItemsSummary ") const token = data.token; const apiUrl = 'https://local.com/v1/items/summary'; const payload = JSON.stringify([{ site_id: "056", supc: "4212791" }]) const headers = { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }; const response = http.post(apiUrl,payload, { headers }); console.log(`Response status: ${response.status}`); requestTrend3.add(response.timings.duration) // 修正变量名 sleep(1); } export function handleSummary(data) { return { 'k6summary.html': htmlReport(data, { debug: false }), stdout: textSummary(data, { indent: ' ', enableColors: true }), } }
关键修改说明
setup()函数:将令牌生成逻辑移至此处,确保仅执行一次,生成的令牌通过返回值传递给所有测试函数。- 响应体丢弃控制:在令牌请求中单独设置
discardResponseBodies: false,既保留全局配置的优化,又能获取令牌响应体。 - 错误处理:添加状态码检查和令牌存在性验证,提前发现问题并终止测试。
- 变量名修正:统一使用
response变量名,避免未定义错误。 - Trend名称修正:将重复的
Request2改为Request3,避免统计数据混淆。
内容的提问来源于stack exchange,提问作者JokerFanJack
相关产品推荐
相关产品推荐

