2016-06-19 12 views
5

Utilizzo un server Web Vert.x per servire un'app React come contenuto statico. Voglio che questo sia pubblicato dal percorso /, quindi all'interno dell'app React ha il proprio instradamento utilizzando react-router che dovrebbe decidere quale pagina mostrare.Distribuzione di un'app rect a una sola pagina utilizzando il server web java vert.x

Finora ho il seguente:

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 -> { // This serves up the React app 
    event.response().sendFile("webroot/index.html").end(); 
}); 
server.requestHandler(router::accept).listen(12001); 

Questo funziona come previsto se comincio richiedendo localhost:12001 e anche gestisce correttamente il percorso cambia da quel momento in poi. Tuttavia, se provo ad aggiornare una delle pagine che ha un percorso gestito dallo react router, ho un sacco di errori generati nei registri del server (la pagina però si carica correttamente).

Qualcuno sa qual è il problema qui e come risolverlo?

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) 
+0

Penso che reagiscono sta generando nuovi URL che cambiano il percorso in modo che quando si aggiorna il browser tenta di recuperare quel percorso che non esiste sul backend vert.x. Penso che sia necessario scrivere alcune regole per mappare questi percorsi personalizzati nel proprio file html. Forse dovresti pubblicare i percorsi generati in modo da poter aiutare a tradurre poi nel tuo file html. –

+0

Vedi cosa succede in Chrome Console quando aggiorni la pagina. Lì dovresti vedere, quando i problemi sono falliti. Potresti quindi allegare l'immagine delle richieste non riuscite. – haschibaschi

+0

Quale versione di Vert.x stai usando? – Vadeg

risposta

1

ho provato numerosi approcci diversi con questo problema ed ho ottenuto nulla. Invece ho deciso di scrivere il mio handler che si comporta come voglio io e non ho alcun errore mostrato nella mia domanda originale.

import io.vertx.core.Handler; 
import io.vertx.core.http.HttpServerRequest; 
import io.vertx.ext.web.RoutingContext; 
import org.apache.logging.log4j.LogManager; 
import org.apache.logging.log4j.Logger; 

public class ReactAppHandler implements Handler<RoutingContext> { 

    private static final Logger LOGGER = LogManager.getLogger(ReactAppHandler.class); 

    private static final String WEB_ROOT_DIR = "webroot"; 
    private static final String INDEX_HTML = "/index.html"; 

    @Override 
    public void handle(RoutingContext event) { 

     HttpServerRequest request = event.request(); 
     String path = event.normalisedPath(); 

     LOGGER.info("Received a request for [" + path + "]."); 

     String requestedFilepath = path; 

     if ("/".equals(requestedFilepath)) { 
      LOGGER.info("Requested file is root path. Remapping to return the index page."); 
      requestedFilepath = INDEX_HTML; 
     } 

     final String fileToCheck = WEB_ROOT_DIR + requestedFilepath; 
     LOGGER.info("Checking if file exists at [" + fileToCheck + "]."); 

     event.vertx().fileSystem().exists(fileToCheck, fileExistsCheck -> { 

      String fileToSend = WEB_ROOT_DIR + INDEX_HTML; 

      if (fileExistsCheck.succeeded() && fileExistsCheck.result()) { 
       LOGGER.info("File exists at path."); 
       fileToSend = fileToCheck; 
      } else { 
       LOGGER.info("Could not find requested file, the index page will be returned instead."); 
      } 

      LOGGER.info("Returning file [" + fileToSend + "]."); 
      request.response().sendFile(fileToSend); 
     }); 
    } 
} 
+0

Il comportamento che stai descrivendo nel tuo gestore non è quello che stavi chiedendo. Quello che dovresti fare è un semplice gestore che controlla se il file esiste e quando non reindirizza a index.html. In questo modo hai tutte le funzionalità del gestore statico con supporto cache, ecc. –

2

In caso di restituzione dei file non si deve chiamare il metodo fine, qui:

router.route(HttpMethod.GET, "/*").handler(StaticHandler.create()).failureHandler(event -> { // This serves up the React app 
    event.response().sendFile("webroot/index.html").end(); 
}); 

La ragione è che l'invio del file è una chiamata asincrona che pompare il file alla risposta in un ottimizzato modo e quando chiami fine stai dicendo chiudi la risposta ORA!

Quello che sembra stia accadendo è che il tuo file è piuttosto piccolo, quindi il SO può pomparlo subito in un colpo solo (così il tuo browser lo riceve ancora correttamente) ma provi a chiudere la connessione quando il sistema operativo ha già fatto è per te.

Che cosa si dovrebbe avere è:

router.route(HttpMethod.GET, "/*").handler(StaticHandler.create()).failureHandler(event -> { // This serves up the React app 
    event.response().sendFile("webroot/index.html"); 
}); 
+0

Grazie per questo. L'ho provato e sembra che questo risolva una delle eccezioni, tuttavia mi sembra di ottenere ancora l'errore 'java.lang.IllegalStateException: Head già scritto'. –

Problemi correlati