使用nock拦截aws-sdk-js请求时如何无需配置有效AWS凭证?
解决方案
问题根因
该报错的核心原因是aws-sdk在发起业务SSM请求前,会默认从本地配置文件、环境变量、云实例元数据、STS服务等多个路径尝试加载有效凭证,本地无有效凭证时,SDK的凭证加载逻辑会提前抛出错误,尚未执行到你配置的SSM请求拦截逻辑。
修复步骤
1. 预配置伪造静态凭证
在单元测试的全局初始化阶段,直接给aws-sdk写入固定的假凭证,跳过SDK的真实凭证加载流程:
const AWS = require('aws-sdk'); beforeAll(() => { // 配置假凭证和对应region,参数可任意填写 AWS.config.update({ accessKeyId: 'mock-ak-123', secretAccessKey: 'mock-sk-456', region: 'us-west-1', }); // 禁用SDK的远程凭证拉取逻辑,避免触发STS/元数据接口调用 AWS.config.credentials = new AWS.Credentials('mock-ak-123', 'mock-sk-456'); });
2. 开启nock严格网络拦截
配置nock禁止所有未被规则匹配的网络请求,彻底避免真实请求外发,可直接在无网络环境运行测试:
const nock = require('nock'); beforeAll(() => { // 禁止所有未拦截的网络请求 nock.disableNetConnect(); // 如果有本地服务调用需求可单独放开,比如nock.enableNetConnect('127.0.0.1') }); afterEach(() => { // 单测结束后清理所有拦截规则,避免用例间相互影响 nock.cleanAll(); }); afterAll(() => { // 所有测试结束后恢复网络权限 nock.enableNetConnect(); });
3. 补充漏拦截的请求
如果配置后依然报错,可在运行测试时添加环境变量NOCK_DEBUG=true,会打印所有未被nock匹配的请求,可根据输出补充对应的拦截规则,比如SDK自动调用的STS接口等。
完整单元测试示例
const nock = require('nock'); const AWS = require('aws-sdk'); // 替换为你自己的业务逻辑模块 const { getSsmParameter } = require('./src/ssm-utils'); // 全局初始化 beforeAll(() => { AWS.config.update({ accessKeyId: 'mock-ak-123', secretAccessKey: 'mock-sk-456', region: 'us-west-1', }); AWS.config.credentials = new AWS.Credentials('mock-ak-123', 'mock-sk-456'); nock.disableNetConnect(); }); afterEach(() => { nock.cleanAll(); }); afterAll(() => { nock.enableNetConnect(); }); test('getSsmParameter 正常返回mock值,无真实请求发出', async () => { // 构造SSM请求拦截 const ssmMock = nock('https://ssm.us-west-1.amazonaws.com:443') .post('/', { Name: '/my-parameter' }) .reply(200, { "Parameter": { "ARN": "arn:aws:ssm:us-west-1:111222333444:parameter/my-parameter", "DataType": "text", "LastModifiedDate": 1617149434.735, "Name": "/my-parameter", "Type": "String", "Value": "myvalue", "Version": 4 } }, [ 'x-amzn-RequestId', '8885bb26-9018-4e9e-8b2e-56232e46ae17' ]).persist(); // 调用业务逻辑 const res = await getSsmParameter('/my-parameter'); // 断言返回结果正确 expect(res).toBe('myvalue'); // 断言拦截规则已命中,确认无真实请求发出 expect(ssmMock.isDone()).toBe(true); });
注意事项
- 确认nock拦截的域名中region参数和你代码里配置的AWS region完全一致,否则会匹配失败
- 如果调用SSM接口时传入了
WithDecryption: true等额外参数,需要在nock的post匹配规则中同步添加对应参数,否则会匹配失败 - 集成测试阶段不需要mock凭证和nock拦截,直接移除上述单测配置即可调用真实AWS服务
内容的提问来源于stack exchange,提问作者Chip
相关产品推荐
相关产品推荐

