javavert.xvertx-httpclient

Getting java.lang.IllegalStateException: Response head already sent, while hitting API in Vert.x


I am new to vert.x and trying to setup server and route apis. I am following this tutorial: https://youtu.be/sAVJDyQd4j4

Here is the code:

package com..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) {
//        System.out.println("Hello world!");
        Vertx vertx=Vertx.vertx();

        Router router=Router.router(vertx);
//        router.route("/something")
//                .handler(routingContext->{
//                    HttpServerResponse response=routingContext.response();
//                    response.putHeader("content-type","text/plain");
//                    response.end("Hi Human, it's vertx you just made");
//                });
        Route handler1=router.route("/hello")
                .handler(routingContext->{
                    HttpServerResponse response=routingContext.response();
                    response.setChunked(true);  //for multiple routes, using setchunked, this is going to stream the data like reactive application where we can push the data from server to UIs
                    response.write("Hi Human, This is hello1");

                    //The below part is where we are using vertex and a scheduler to identify is there any thing else to match.
                    // Using which we are not going to immediately call the next router,
                    // rather just add the vertex code to sy that after this particular router, allow us to the next when,
                    // this like adding filters and going through a chaining process.
                    routingContext.
                            vertx()
                            .setTimer(5000, tid -> routingContext.next()); //5sec timer, and us the routingContext to go to the next router, so this basically does the search for the next router with the same name.
                });

        Route handler2=router.route("/hello")
                .handler(routingContext->{
                    HttpServerResponse response=routingContext.response();
                    //we dont need to chunk it here, as we have already chunked it above
                    //response.setChunked(true);  //for multiple routes, using setchunked, this is going to stream the data like reactive application where we can push the data from server to UIs
                    response.write("Hi Human, This is hello2");

                    //The below part is where we are using vertex and a scheduler to identify is there any thing else to match.
                    // Using which we are not going to immediately call the next router,
                    // rather just add the vertex code to sy that after this particular router, allow us to the next when,
                    // this like adding filters and going through a chaining process.
                    routingContext.
                            vertx()
                            .setTimer(5000, tid -> routingContext.next()); //5sec timer, and us the routingContext to go to the next router, so this basically does the search for the next router with the same name.
                });

        Route handler3=router.route("/hello ")
                .handler(routingContext->{
                    HttpServerResponse response=routingContext.response();
                    //we dont need to chunk it here, as we have already chunked it above
                    //response.setChunked(true);  //for multiple routes, using setchunked, this is going to stream the data like reactive application where we can push the data from server to UIs
                    response.write("Hi Human, This is hello3");
                    response.end();
                });


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

    }
}

And I am getting this error:

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)

What I have tried to fix this is:

  1. Used try catch everywhere where this line is present: routingContext.vertx().setTimer(5000, tid -> routingContext.next());
  2. Also have tried removing response.write("Hi Human, This is hello2"); from everywhere and just keeping it to the second last router.

But both of the methods didn't fix it. Any idea what could be the possible cause for this and hot to fix this?


Solution

  • The third route definition is different from others, it contains a space:

    Route handler3=router.route("/hello ")
    

    So when routingContext.next() is invoked in the second route handler, the Router does not find a route and tries to set the status code to 404.

    Change the definition to:

    Route handler3=router.route("/hello")
    

    And the error should go away.