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

使用RestAssured编写POST接口JUnit测试时遇NoHttpResponseException问题

解决RestAssured POST测试中org.apache.http.NoHttpResponseException异常

我来帮你排查这个问题,你遇到的org.apache.http.NoHttpResponseException本质是RestAssured向localhost:8080发送请求后,没有收到任何响应——大概率是你的Mock服务器没正确处理请求,或者请求本身存在配置问题,咱们一步步来解决:

1. 先确认MockRESTServer的有效性

你用的MockRESTServer看起来是自定义的Mock服务器,首先要确保它真的在8080端口正常启动,并且能正确路由/create的POST请求:

  • 可以先跳过RestAssured,直接用curl命令测试Mock服务器:
    curl -X POST -H "Content-Type: application/json" -d '{"name":"policy123"}' http://localhost:8080/create
    
    如果curl也返回无响应,那问题出在Mock服务器本身,检查它的启动逻辑、路由映射是否正确,比如是否真的把PolicyResource绑定到了根路径。

2. 显式配置RestAssured的基础地址

虽然你代码里的请求路径看起来没问题,但显式指定base URI和端口能避免默认配置的潜在问题,修改测试代码:

@Test
public final void testCreatePolicy() {
    // 显式设置基础地址
    RestAssured.baseURI = "http://localhost";
    RestAssured.port = 8080;

    Policy policy=new Policy();
    policy.setName("policy123");
    RestAssured.with()
        .contentType("application/json")
        .accept("application/json")
        .body(policy)
        .post("/create")
        .then()
        .assertThat()
        .statusCode(200);
}

3. 检查Policy类的JSON序列化

RestAssured需要把Policy对象序列化成JSON字符串才能发送请求,如果你的Policy类没有正确配置序列化(比如缺少Jackson/Gson的注解,或者没有无参构造函数),会导致请求体格式错误,Mock服务器可能直接断开连接:

  • 给Policy类添加必要的序列化配置,比如用Jackson的注解:
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    public class Policy {
        @JsonProperty("name")
        private String name;
    
        // 必须要有无参构造函数,Jackson需要它来反序列化
        public Policy() {}
    
        public Policy(String name) {
            this.name = name;
        }
    
        // getter和setter
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }
    
  • 或者手动把对象转成JSON字符串再传入body,避免自动序列化的问题:
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    @Test
    public final void testCreatePolicy() throws Exception {
        RestAssured.baseURI = "http://localhost";
        RestAssured.port = 8080;
    
        Policy policy=new Policy();
        policy.setName("policy123");
        
        ObjectMapper mapper = new ObjectMapper();
        String policyJson = mapper.writeValueAsString(policy);
    
        RestAssured.with()
            .contentType("application/json")
            .accept("application/json")
            .body(policyJson)
            .post("/create")
            .then()
            .assertThat()
            .statusCode(200);
    }
    

4. 简化Mock服务器的响应逻辑

你的PolicyResource方法里的响应代码可以简化,Response.ok()已经默认返回200状态码,重复设置status(200)虽然没问题,但可以改成更简洁的写法,确保响应能正确返回:

@POST
@Path("/create")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response test(Policy messageBody) {
    System.out.println("policy: "+messageBody);
    // 简化响应逻辑
    return Response.ok().build();
}

5. 排查端口占用问题

如果以上步骤都没问题,检查8080端口是否被其他程序占用,导致Mock服务器启动失败:

  • Windows系统:打开命令提示符执行netstat -ano | findstr :8080,查看PID对应的程序,结束占用端口的进程后重新启动测试。
  • Linux/Mac系统:执行lsof -i :8080查看占用端口的进程,用kill -9 <PID>结束进程。

附上你提供的原始代码和异常信息,方便对照:

测试类代码

public class PolicyResourceTest {
    private static MockRESTServer server;
    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        server = new MockRESTServer(8080, new PolicyResource());
        server.start();
    }
    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        server.stop();
    }
    @Test
    public final void testCreatePolicy() {
        Policy policy=new Policy();
        policy.setName("policy123");
        RestAssured.with()
            .contentType("application/json")
            .accept("application/json")
            .body(policy)
            .post("/create")
            .then()
            .assertThat()
            .statusCode(200);
    }
}

资源类代码

@Path("/")
public class PolicyResource {
    @POST
    @Path("/create")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public Response test( Policy messageBody) {
        System.out.println("policy: "+messageBody);
        return Response.ok().status(200).build();
    }
}

异常信息

org.apache.http.NoHttpResponseException: localhost:8080 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.AbstractHttpClientConnection.receiveResponseHeader(AbstractHttpClientConnection.java:281)
at org.apache.http.impl.conn.DefaultClientConnection.receiveResponseHeader(DefaultClientConnection.java:257)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.receiveResponseHeader(ManagedClientConnectionImpl.java:207)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.client.DefaultRequestDirector.tryExecute(DefaultRequestDirector.java:684)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:486)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at org.apache.http.client.HttpClient$execute$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at io.restassured.internal.RequestSpecificationImpl$RestAssuredHttpBuilder.doRequest(RequestSpecificationImpl.groovy:2028)
at io.restassured.internal.http.HTTPBuilder.post(HTTPBuilder.java:349)
at io.restassured.internal.http.HTTPBuilder$post$2.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
at io.restassured.internal.RequestSpecificationImpl.sendRequest(RequestSpecificationImpl.groovy:1202)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:13:24