You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JMeter进行API性能测试时排查403认证错误

问题:API性能测试持续返回403认证错误(预期200)

我正在对应用程序API开展性能测试,发送请求时始终收到403(认证错误)响应,但预期应为200(请求成功)。

已完成的排查步骤:

  • 向API发送包含有效参数的请求;
  • 请求中携带了我认为有效的Bearer Token;
  • 验证URL构造正确;
  • 测试无需认证的健康检查端点,可正常返回结果。

尽管采取上述措施,仍持续收到403错误,说明Bearer Token的配置可能存在问题——即便我认为Token有效,API仍无法识别或接受它。

以下是我使用的JMeter Java代码:

package initialization;

import org.apache.jmeter.control.LoopController;
import org.apache.jmeter.control.gui.LoopControlPanel;
import org.apache.jmeter.control.gui.TestPlanGui;
import org.apache.jmeter.engine.JMeterEngineException;
import org.apache.jmeter.engine.StandardJMeterEngine;

import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerProxy;
import org.apache.jmeter.reporters.ResultCollector;
import org.apache.jmeter.reporters.Summariser;

import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.threads.gui.ThreadGroupGui;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.collections.ListedHashTree;
import org.testng.annotations.Test;

import java.io.IOException;

public class JmeterSetup {
    private static final String API_URL = "";
    private static final String ACCEPT_HEADER = "*/*";
    private static final String AUTHORIZATION_HEADER = "Bearer ActualBearer";
    private static final String Param = "sd";

    @Test
    void givenJMeterScript_whenUsingCode_thenExecuteViaJavaProgram() throws IOException, JMeterEngineException {

        JMeterUtils.setJMeterHome(".\\Downloads\\apache-jmeter-5.6.3\\bin\\jmeter.properties");
        String jmeterFile = ".\\Downloads\\apache-jmeter-5.6.3\\bin\\jmeter.properties";

        JMeterUtils.loadJMeterProperties(jmeterFile);
        JMeterUtils.initLocale();
        StandardJMeterEngine jmeter = new StandardJMeterEngine();

        HTTPSamplerProxy httpSampler = getHttpSamplerProxy();

        LoopController loopController = getLoopController();

        ThreadGroup threadGroup = getThreadGroup(loopController);

        TestPlan testPlan = getTestPlan(threadGroup);

        ListedHashTree testPlanTree = new ListedHashTree();
        ListedHashTree threadGroupHashTree = (ListedHashTree) testPlanTree.add(testPlan, threadGroup);
        threadGroupHashTree.add(httpSampler);


        Summariser summer = null;
        String summariserName = JMeterUtils.getPropDefault("summariser.name", "summary");

        if (summariserName.length() > 0) {
            summer = new Summariser(summariserName);
        }

        String logFile = "output-logs.jtl";
        ResultCollector logger = new ResultCollector(summer);
        logger.setFilename(logFile);
        testPlanTree.add(testPlanTree.getArray()[0], logger);


        jmeter.configure(testPlanTree);
        jmeter.run();


        System.out.println("Test completed. See output-logs.jtl file for results");
        System.out.println("JMeter .jmx script is available at script.jmx");
    }

    private static LoopController getLoopController() {
        LoopController loopController = new LoopController();
        loopController.setLoops(1);
        loopController.setFirst(true);
        loopController.setProperty(TestElement.TEST_CLASS, LoopController.class.getName());
        loopController.setProperty(TestElement.GUI_CLASS, LoopControlPanel.class.getName());
        loopController.initialize();
        return loopController;
    }


    private static HTTPSamplerProxy getHttpSamplerProxy() {
        HTTPSamplerProxy httpSampler = new HTTPSamplerProxy();
        httpSampler.setProtocol("https");
        httpSampler.setDomain("ApplicationDomain");
        httpSampler.setPath("Path");
        httpSampler.setMethod("GET");

        // Create a HeaderManager and add the headers
        HeaderManager headerManager = new HeaderManager();
        headerManager.add(new org.apache.jmeter.protocol.http.control.Header("accept", ACCEPT_HEADER));
        headerManager.add(new org.apache.jmeter.protocol.http.control.Header("Authorization", AUTHORIZATION_HEADER));
        headerManager.add(new org.apache.jmeter.protocol.http.control.Header("param", Param));
        httpSampler.setHeaderManager(headerManager);

        // Set the properties for the HTTPSamplerProxy
        httpSampler.setProperty(TestElement.GUI_CLASS, HttpTestSampleGui.class.getName());
        httpSampler.setProperty(TestElement.NAME, "API Request");

        return httpSampler;
    }


    private static TestPlan getTestPlan(ThreadGroup threadGroup) {
        TestPlan testPlan = new TestPlan("Sample Test Plan");
        testPlan.setProperty(TestElement.TEST_CLASS, TestPlan.class.getName());
        testPlan.setProperty(TestElement.GUI_CLASS, TestPlanGui.class.getName());
        return testPlan;
    }

    private static ThreadGroup getThreadGroup(LoopController loopController) {
        ThreadGroup threadGroup = new ThreadGroup();
        threadGroup.setName("Sample Thread Group");
        threadGroup.setNumThreads(10);
        threadGroup.setRampUp(5);
        threadGroup.setSamplerController(loopController);
        threadGroup.setProperty(TestElement.TEST_CLASS, ThreadGroup.class.getName());
        threadGroup.setProperty(TestElement.GUI_CLASS, ThreadGroupGui.class.getName());
        return threadGroup;
    }
}

排查与修复建议

  1. 验证Bearer Token的有效性与格式

    • 替换AUTHORIZATION_HEADER中的ActualBearer为真实Token,确保Bearer 与Token之间仅有一个空格,无多余字符;部分API对Bearer的大小写敏感,需严格遵循要求。
    • 用Postman或curl直接调用API并携带同一Token,确认是否返回200。若仍返回403,说明Token本身无效(过期、权限不足、受众不匹配等),需重新获取有效Token。
  2. 修正JMeter初始化错误

    • JMeterUtils.setJMeterHome()方法需传入JMeter根目录路径,而非properties文件路径。正确代码:
      JMeterUtils.setJMeterHome(".\\Downloads\\apache-jmeter-5.6.3");
      String jmeterFile = ".\\Downloads\\apache-jmeter-5.6.3\\bin\\jmeter.properties";
      
    • 该错误会导致JMeter无法正确加载配置,可能影响请求发送逻辑。
  3. 补全API域名与路径

    • 将httpSampler.setDomain("ApplicationDomain")和httpSampler.setPath("Path")替换为真实的API域名与路径,确保与健康检查端点的环境一致。
  4. 排查请求头与并发限制

    • 确认API是否需要额外请求头(如Content-Type),若有需补充到HeaderManager中。
    • 暂时将线程组的numThreads改为1、rampUp改为0,排除并发请求触发API限流或认证频率限制的可能。
  5. 抓包或查看日志分析请求细节

    • 查看output-logs.jtl文件中的请求头与响应详情,确认Authorization头是否正确发送;或用抓包工具(如Fiddler)捕获实际请求,对比预期与实际发送的内容差异。

内容的提问来源于stack exchange,提问作者Nate101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 16:25:58