title: Serving up a single page rect app using java vert.x web server
body: <p>I'm making use of a <code>Vert.x</code> web server to serve up a <code>React</code> app as static content. I want this to be served up from the path <code>/</code>, then within the <code>React</code> app it has its own routing using <code>react-router</code> which should decide which page to show.</p>
  
  <p>So far I have the following:</p>
  
  <pre><code>Vertx vertx = Vertx.vertx();
  HttpServer server = vertx.createHttpServer();
  Router router = Router.router(vertx);
  router.route().handler(BodyHandler.create());
  router.route(HttpMethod.POST, "/rest/foo").handler(new FooHandler());
  router.route(HttpMethod.GET, "/*").handler(StaticHandler.create()).failureHandler(event -&gt; { // This serves up the React app
      event.response().sendFile("webroot/index.html").end();
  });
  server.requestHandler(router::accept).listen(12001);
  </code></pre>
  
  <p>This works as expected if I start by requesting <code>localhost:12001</code> and it also correctly handles the path changes from that point onwards. However if I try to refresh one of the pages which has a path handled by the <code>react router</code> then I get a bunch of error generated in the server logs (the page does load correctly though).</p>
  
  <p>Does anybody know what the issue is here and how to fix it?</p>
  
  <pre><code>SEVERE: Unexpected exception in route
  java.lang.IllegalStateException: Response has already been written
      at io.vertx.core.http.impl.HttpServerResponseImpl.checkWritten(HttpServerResponseImpl.java:561)
      at io.vertx.core.http.impl.HttpServerResponseImpl.end0(HttpServerResponseImpl.java:389)
      at io.vertx.core.http.impl.HttpServerResponseImpl.end(HttpServerResponseImpl.java:328)
      at co.uk.foo.webserver.server.WebServer.lambda$initialiseRoutes$0(WebServer.java:67)
      at co.uk.foo.webserver.server.WebServer$$Lambda$4/1197365356.handle(Unknown Source)
      at io.vertx.ext.web.impl.RouteImpl.handleFailure(RouteImpl.java:227)
      at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:76)
      at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:94)
      at io.vertx.ext.web.impl.RoutingContextImpl.doFail(RoutingContextImpl.java:355)
      at io.vertx.ext.web.impl.RoutingContextImpl.fail(RoutingContextImpl.java:119)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.lambda$sendStatic$2(StaticHandlerImpl.java:198)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl$$Lambda$17/1050258443.handle(Unknown Source)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.wrapInTCCLSwitch(StaticHandlerImpl.java:245)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.getFileProps(StaticHandlerImpl.java:264)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.sendStatic(StaticHandlerImpl.java:184)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.handle(StaticHandlerImpl.java:141)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.handle(StaticHandlerImpl.java:51)
      at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:221)
      at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)
      at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:94)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.doEnd(BodyHandlerImpl.java:155)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.end(BodyHandlerImpl.java:141)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl.lambda$handle$34(BodyHandlerImpl.java:61)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl$$Lambda$14/1403708668.handle(Unknown Source)
      at io.vertx.core.http.impl.HttpServerRequestImpl.handleEnd(HttpServerRequestImpl.java:411)
      at io.vertx.core.http.impl.ServerConnection.handleEnd(ServerConnection.java:286)
      at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:404)
      at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:134)
      at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:515)
      at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:421)
      at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$20(VertxHttpHandler.java:80)
      at io.vertx.core.http.impl.VertxHttpHandler$$Lambda$16/1532360211.run(Unknown Source)
      at io.vertx.core.impl.ContextImpl.lambda$wrapTask$18(ContextImpl.java:333)
      at io.vertx.core.impl.ContextImpl$$Lambda$11/511598695.run(Unknown Source)
      at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:225)
      at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:80)
      at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:124)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318)
      at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304)
      at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:276)
      at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:263)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318)
      at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304)
      at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
      at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
      at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
      at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
      at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
      at java.lang.Thread.run(Thread.java:745)
  
  Jun 26, 2016 4:22:08 PM io.vertx.ext.web.impl.RoutingContextImplBase
  SEVERE: Unexpected exception in route
  java.lang.IllegalStateException: Head already written
      at io.vertx.core.http.impl.HttpServerResponseImpl.doSendFile(HttpServerResponseImpl.java:434)
      at io.vertx.core.http.impl.HttpServerResponseImpl.sendFile(HttpServerResponseImpl.java:334)
      at io.vertx.core.http.impl.HttpServerResponseImpl.sendFile(HttpServerResponseImpl.java:52)
      at io.vertx.core.http.HttpServerResponse.sendFile(HttpServerResponse.java:275)
      at io.vertx.core.http.HttpServerResponse.sendFile(HttpServerResponse.java:262)
      at co.uk.foo.webserver.server.WebServer.lambda$initialiseRoutes$0(WebServer.java:67)
      at co.uk.foo.webserver.server.WebServer$$Lambda$4/1197365356.handle(Unknown Source)
      at io.vertx.ext.web.impl.RouteImpl.handleFailure(RouteImpl.java:227)
      at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:76)
      at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:94)
      at io.vertx.ext.web.impl.RoutingContextImpl.doFail(RoutingContextImpl.java:355)
      at io.vertx.ext.web.impl.RoutingContextImpl.fail(RoutingContextImpl.java:119)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.lambda$sendStatic$2(StaticHandlerImpl.java:189)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl$$Lambda$17/1050258443.handle(Unknown Source)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.getFileProps(StaticHandlerImpl.java:284)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.sendStatic(StaticHandlerImpl.java:184)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.handle(StaticHandlerImpl.java:141)
      at io.vertx.ext.web.handler.impl.StaticHandlerImpl.handle(StaticHandlerImpl.java:51)
      at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:221)
      at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:78)
      at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:94)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.doEnd(BodyHandlerImpl.java:155)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.end(BodyHandlerImpl.java:141)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl.lambda$handle$34(BodyHandlerImpl.java:61)
      at io.vertx.ext.web.handler.impl.BodyHandlerImpl$$Lambda$14/1403708668.handle(Unknown Source)
      at io.vertx.core.http.impl.HttpServerRequestImpl.handleEnd(HttpServerRequestImpl.java:411)
      at io.vertx.core.http.impl.ServerConnection.handleEnd(ServerConnection.java:286)
      at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:404)
      at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:134)
      at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:515)
      at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:421)
      at io.vertx.core.http.impl.VertxHttpHandler.lambda$channelRead$20(VertxHttpHandler.java:80)
      at io.vertx.core.http.impl.VertxHttpHandler$$Lambda$16/1532360211.run(Unknown Source)
      at io.vertx.core.impl.ContextImpl.lambda$wrapTask$18(ContextImpl.java:333)
      at io.vertx.core.impl.ContextImpl$$Lambda$11/511598695.run(Unknown Source)
      at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:225)
      at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:80)
      at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:124)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318)
      at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304)
      at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:276)
      at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:263)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:318)
      at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:304)
      at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
      at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:131)
      at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
      at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
      at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
      at java.lang.Thread.run(Thread.java:745)
  </code></pre>