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

Vert.x调用API时出现Response head already sent异常的排查与解决

Vert.x路由链调用异常问题解决

问题背景

我是Vert.x新手,正在搭建服务器和路由API,调用接口时触发java.lang.IllegalStateException: Response head already sent异常,相关代码、异常信息如下:

代码示例

package com.yashkirat.zee.vertx;

import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;

public class Main {
    public static void main(String[] args) {
        Vertx vertx=Vertx.vertx();

        Router router=Router.router(vertx);
        Route handler1=router.route("/hello")
                .handler(routingContext->{
                    HttpServerResponse response=routingContext.response();
                    response.setChunked(true);
                    response.write("Hi Human, This is hello1");

                    routingContext.vertx()
                            .setTimer(5000, tid -> routingContext.next());
                });

        Route handler2=router.route("/hello")
                .handler(routingContext->{
                    HttpServerResponse response=routingContext.response();
                    response.write("Hi Human, This is hello2");

                    routingContext.vertx()
                            .setTimer(5000, tid -> routingContext.next());
                });

        Route handler3=router.route("/hello ")
                .handler(routingContext->{
                    HttpServerResponse response=routingContext.response();
                    response.write("Hi Human, This is hello3");
                    response.end();
                });

        HttpServer httpServer=vertx.createHttpServer();
        httpServer.requestHandler(router).listen(8091);
    }
}

异常信息

SEVERE: Unhandled exception
java.lang.IllegalStateException: Response head already sent
    at io.vertx.core.http.impl.Http1xServerResponse.checkHeadWritten(Http1xServerResponse.java:709)
    at io.vertx.core.http.impl.Http1xServerResponse.setStatusCode(Http1xServerResponse.java:149)
    at io.vertx.ext.web.impl.RoutingContextImpl.checkHandleNoMatch(RoutingContextImpl.java:156)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:142)
    at com.yashkirat.zee.vertx.Main.lambda$null$2(Main.java:49)
    at io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:948)
    at io.vertx.core.impl.VertxImpl$InternalTimerHandler.handle(VertxImpl.java:919)
    at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:55)
    at io.vertx.core.impl.DuplicatedContext.emit(DuplicatedContext.java:158)
    at io.vertx.core.impl.ContextInternal.emit(ContextInternal.java:194)
    at io.vertx.core.impl.VertxImpl$InternalTimerHandler.run(VertxImpl.java:937)
    at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
    at io.netty.util.concurrent.ScheduledFutureTask.run(ScheduledFutureTask.java:153)
    at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
    at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
    at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
    at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.lang.Thread.run(Thread.java:750)

尝试过的修复方法

  • 在所有包含routingContext.vertx().setTimer(5000, tid -> routingContext.next());的位置添加try-catch;
  • 移除所有response.write("Hi Human, This is hello2");语句,只保留倒数第二个路由中的该语句。

以上两种方法均未解决问题。


问题原因

  1. 路由路径不匹配:handler3的路由是"/hello "(末尾多了一个空格),和请求的/hello路径不匹配。当handler2调用routingContext.next()后,Vert.x找不到后续匹配的路由,会自动尝试返回404状态码,但此时响应头已经因之前的response.write()操作被发送,无法再修改状态码,触发异常。
  2. 响应生命周期冲突:调用response.write()时,即使开启了chunked模式,Vert.x也会自动发送响应头。后续Vert.x尝试设置404状态码时,发现响应头已发送,抛出Response head already sent异常。

修复方案

步骤1:修正路由路径

将handler3的路由从"/hello "改为"/hello",确保三个路由都匹配同一个请求路径,让routingContext.next()能正确找到下一个处理器。

步骤2:完善响应头设置(可选但建议)

在第一个handler中添加content-type响应头,避免客户端解析响应内容时出现问题。

修正后的完整代码

package com.yashkirat.zee.vertx;

import io.vertx.core.Vertx;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.ext.web.Route;
import io.vertx.ext.web.Router;

public class Main {
    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        Router router = Router.router(vertx);

        Route handler1 = router.route("/hello")
                .handler(routingContext -> {
                    HttpServerResponse response = routingContext.response();
                    response.setChunked(true);
                    response.putHeader("content-type", "text/plain"); // 添加内容类型头
                    response.write("Hi Human, This is hello1\n");

                    routingContext.vertx()
                            .setTimer(5000, tid -> routingContext.next());
                });

        Route handler2 = router.route("/hello")
                .handler(routingContext -> {
                    HttpServerResponse response = routingContext.response();
                    response.write("Hi Human, This is hello2\n");

                    routingContext.vertx()
                            .setTimer(5000, tid -> routingContext.next());
                });

        Route handler3 = router.route("/hello") // 移除末尾空格
                .handler(routingContext -> {
                    HttpServerResponse response = routingContext.response();
                    response.write("Hi Human, This is hello3\n");
                    response.end(); // 结束响应
                });

        HttpServer httpServer = vertx.createHttpServer();
        httpServer.requestHandler(router).listen(8091);
    }
}

注意事项

  • 确保请求链最终能走到调用response.end()的逻辑,不要让请求无疾而终,否则Vert.x会自动尝试返回404,引发响应头冲突。
  • 开启chunked模式后,所有write操作会流式发送,最终必须调用end()来结束响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 23:15:57