使用k6+Webpack测试AWS Cognito授权接口时遇URL未定义错误
问题:k6搭配Webpack调用AWS Cognito接口时出现
ReferenceError: URL is not defined 问题背景
对需AWS Cognito授权的应用接口做性能测试,选用k6+Webpack组合。调用await client.initiateAuth(params)(client为CognitoIdentityProvider实例)时抛出ReferenceError: URL is not defined异常。调试发现:不使用Webpack时,await client.config.endpoint()能返回正确Cognito地址;使用Webpack则触发相同错误。
相关代码及运行日志如下:
index.js
import http from 'k6/http'; import { Rate, Trend } from 'k6/metrics'; import { check } from 'k6'; import { getToken } from "./cognito-service"; var errors = new Rate("errors"); var trends = new Trend("trends"); export const options = { vus: 1, duration: '10s', }; const token = getToken(); const params = { headers: { 'Authorization': 'Bearer ' + token, }, }; export default function () { const res = http.get('https://myurl.com/api/need/to/test', params); check(res, { 'status was 200': (r) => r.status == 200 }); errors.add(res.error_code); trends.add(res.timings.sending + res.timings.receiving); }
webpack.config.js
const path = require('path'); module.exports = { mode: 'production', entry: { login: './index.js', }, output: { path: path.resolve(__dirname, 'build'), libraryTarget: 'commonjs', filename: '[name].bundle.js', }, module: { rules: [ { test: /\.js$/, use: 'babel-loader' } ], }, target: 'web', externals: /k6(\/.*)?/, };
cognito-service.js
import { CognitoIdentityProvider } from "@aws-sdk/client-cognito-identity-provider"; export const getToken = async () => { const clientId = "XXXXXXXXXX"; const params = { AuthFlow: "USER_PASSWORD_AUTH", ClientId: clientId, AuthParameters: { "USERNAME": "xxxxxx@gmail.com", "PASSWORD": "Test123$" } }; const client = new CognitoIdentityProvider({ region: "eu-central-1" }); try { console.log(client.config); const response = await client.initiateAuth(params); console.log(`Response is -> ${response}`) return response; } catch(error) { console.log(`Err is -> ${error}`); } }
运行日志
> k6 run build/login.bundle.js /\ |‾‾| /‾‾/ /‾‾/ /\ / \ | |/ / / / / \/ \ | ( / ‾‾\ / \ | |\ \ | (‾) | / __________ \ |__| \__\ \_____/ .io INFO[0000] {"apiVersion":"2016-04-18","disableHostPrefix":false,"logger":{},"serviceId":"Cognito Identity Provider","runtime":"browser","requestHandler":{"configProvider":{}},"tls":true,"isCustomEndpoint":false,"systemClockOffset":0,"signingEscapePath":true} source=console INFO[0000] Err is -> ReferenceError: URL is not defined source=console execution: local script: build/login.bundle.js output: - scenarios: (100.00%) 1 scenario, 1 max VUs, 40s max duration (incl. graceful stop): * default: 1 looping VUs for 10s (gracefulStop: 30s) INFO[0000] {"apiVersion":"2016-04-18","disableHostPrefix":false,"logger":{},"serviceId":"Cognito Identity Provider","runtime":"browser","requestHandler":{"configProvider":{}},"tls":true,"isCustomEndpoint":false,"systemClockOffset":0,"signingEscapePath":true} source=console INFO[0000] Err is -> ReferenceError: URL is not defined source=console INFO[0000] {"apiVersion":"2016-04-18","disableHostPrefix":false,"logger":{},"serviceId":"Cognito Identity Provider","runtime":"browser","requestHandler":{"configProvider":{}},"tls":true,"isCustomEndpoint":false,"systemClockOffset":0,"signingEscapePath":true} source=console INFO[0000] Err is -> ReferenceError: URL is not defined source=console
原因分析
- Webpack目标环境不匹配:Webpack配置中
target: 'web'会让AWS SDK判定运行环境为浏览器,但k6的执行环境是基于Go的V8引擎,并非标准浏览器环境,缺少浏览器全局对象URL。 - 异步函数调用时机错误:
getToken是异步函数,在k6全局作用域直接调用const token = getToken()会导致未正确获取到token,且k6不支持在全局作用域执行异步操作。
解决方案
1. 修改Webpack配置,适配k6环境
将Webpack的target改为'node',让AWS SDK使用Node.js环境的API实现,同时添加Node.js核心模块的polyfill:
首先安装依赖:
npm install node-polyfill-webpack-plugin --save-dev
修改后的webpack.config.js:
const path = require('path'); const NodePolyfillPlugin = require('node-polyfill-webpack-plugin'); module.exports = { mode: 'production', entry: { login: './index.js', }, output: { path: path.resolve(__dirname, 'build'), libraryTarget: 'commonjs', filename: '[name].bundle.js', }, module: { rules: [ { test: /\.js$/, use: 'babel-loader' } ], }, target: 'node', externals: /k6(\/.*)?/, plugins: [ new NodePolyfillPlugin() ] };
2. 修正k6脚本中的异步调用逻辑
k6中异步操作需放在setup函数(初始化阶段执行,支持异步)或default函数(需标记为async)中。这里推荐用setup函数预获取token:
修改后的index.js:
import http from 'k6/http'; import { Rate, Trend } from 'k6/metrics'; import { check } from 'k6'; import { getToken } from "./cognito-service"; var errors = new Rate("errors"); var trends = new Trend("trends"); export const options = { vus: 1, duration: '10s', }; // 用setup函数异步获取token,所有VU共享 export async function setup() { const tokenData = await getToken(); return { token: tokenData.AuthenticationResult.IdToken }; } export default function (data) { const params = { headers: { 'Authorization': 'Bearer ' + data.token, }, }; const res = http.get('https://myurl.com/api/need/to/test', params); check(res, { 'status was 200': (r) => r.status == 200 }); errors.add(res.error_code || 0); trends.add(res.timings.sending + res.timings.receiving); }
3. 完善cognito-service.js的返回值与配置
指定AWS SDK运行时为Node.js,确保返回有效token数据:
import { CognitoIdentityProvider } from "@aws-sdk/client-cognito-identity-provider"; export const getToken = async () => { const clientId = "XXXXXXXXXX"; const params = { AuthFlow: "USER_PASSWORD_AUTH", ClientId: clientId, AuthParameters: { "USERNAME": "xxxxxx@gmail.com", "PASSWORD": "Test123$" } }; const client = new CognitoIdentityProvider({ region: "eu-central-1", runtime: 'node' }); try { const response = await client.initiateAuth(params); return response; } catch(error) { console.error(`获取token失败: ${error}`); throw error; } }
验证
重新打包并运行k6脚本:
npm run build k6 run build/login.bundle.js
此时应能正常获取Cognito token,不再抛出URL is not defined异常,接口请求可携带有效授权头。
内容的提问来源于stack exchange,提问作者Tomash Gombosh
相关产品推荐
相关产品推荐

