用VertX服务favicon.ico和其他静态文件

我正在尝试提供一个favicon和一些字体。

object Lion : AbstractVerticle() { @JvmStatic @Throws(IOException::class) fun main(args: Array<String>) { val vertx = Vertx.vertx() val router = Router.router(vertx) router.route().handler(CorsHandler.create("*") .allowedMethod(HttpMethod.GET) .allowedMethod(HttpMethod.POST) .allowedMethod(HttpMethod.OPTIONS) .allowedHeader("X-PINGARUNER") .allowedHeader("Content-Type")) // some json GET / POST routes here router.route().handler(FaviconHandler.create()); router.route().handler(StaticHandler.create()) vertx.createHttpServer().requestHandler { router.accept(it) }.listen(9090) } 

当我转到http://localhost:9090/favicon.ico时, FaviconHandler抛出一个导致“内部服务器错误”的异常。我的图标位于src/main/resources/webroot/favicon.ico

 Oct 22, 2016 11:16:42 PM io.vertx.ext.web.impl.RoutingContextImplBase SEVERE: Unexpected exception in route java.lang.RuntimeException: java.lang.NullPointerException at io.vertx.ext.web.handler.impl.FaviconHandlerImpl.init(FaviconHandlerImpl.java:148) at io.vertx.ext.web.handler.impl.FaviconHandlerImpl.handle(FaviconHandlerImpl.java:155) at io.vertx.ext.web.handler.impl.FaviconHandlerImpl.handle(FaviconHandlerImpl.java:33) at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:215) 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.CorsHandlerImpl.handle(CorsHandlerImpl.java:121) at io.vertx.ext.web.handler.impl.CorsHandlerImpl.handle(CorsHandlerImpl.java:38) at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:215) 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.impl.RouterImpl.accept(RouterImpl.java:79) at Lion$main$8.handle(Lion.kt:90) at Lion$main$8.handle(Lion.kt:43) at io.vertx.core.http.impl.ServerConnection.handleRequest(ServerConnection.java:286) at io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:412) at io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:139) at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.lambda$createConnAndHandle$1(HttpServerImpl.java:712) at io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:314) at io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:190) at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.createConnAndHandle(HttpServerImpl.java:706) at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:570) at io.vertx.core.http.impl.HttpServerImpl$ServerHandler.doMessageReceived(HttpServerImpl.java:522) at io.vertx.core.http.impl.VertxHttpHandler.channelRead(VertxHttpHandler.java:76) at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:122) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:293) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:267) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350) at io.vertx.core.http.impl.HttpServerImpl$Http1xOrHttp2Handler.http1(HttpServerImpl.java:1019) at io.vertx.core.http.impl.HttpServerImpl$Http1xOrHttp2Handler.channelRead(HttpServerImpl.java:990) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:350) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1334) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:372) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:358) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:926) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:129) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:610) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:551) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:465) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:437) at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:873) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.NullPointerException at io.vertx.ext.web.handler.impl.FaviconHandlerImpl$Icon.<init>(FaviconHandlerImpl.java:61) at io.vertx.ext.web.handler.impl.FaviconHandlerImpl$Icon.<init>(FaviconHandlerImpl.java:40) at io.vertx.ext.web.handler.impl.FaviconHandlerImpl.init(FaviconHandlerImpl.java:143) ... 48 more 

删除FaviconHandler和正常的htmljscss文件服务正常,但字体无法服务。

 Failed to decode downloaded font: http://localhost:9090/fonts/glyphicons-halflings-regular.woff /#/tcr:1 OTS parsing error: incorrect file size in WOFF header 

当我直接进入font-url时,浏览器正在尝试将字体作为常规文件下载。

这似乎是一个潜在的解决方案,但是我看到的东西不是我的favicon,只是一个16×16的方块,它的字体扭曲,字体仍然试图下载,仍然在浏览器控制台中的错误。

  router.route("/favicon.ico").handler { it.response().putHeader("Content-Type", "image/x-icon").sendFile("webroot/favicon.ico") } router.route("/fonts/glyphicons-halflings-regular.woff").handler { it.response().putHeader("Content-Type", "application/font-woff").sendFile("webroot/fonts/glyphicons-halflings-regular.woff") } 

所以总结一下,如何使StaticHandler正确地使用正确的MimeTypes服务.woff.ico文件,而不是下载这些文件?

解答

我遇到的第一个问题是,由于某种原因,maven shade没有将所有字体文件复制到jar中。

显式复制构建字体文件和禁用字体的资源过滤似乎已经修复了字体问题。

 <build> <sourceDirectory>${basedir}/src/main/java</sourceDirectory> <resources> <resource> <directory>${basedir}/src/main/resources</directory> <filtering>true</filtering> </resource> <resource> <directory>${basedir}/src/main/resources/fonts</directory> <filtering>false</filtering> </resource> </resources> 

然后从资源目录中提供字体,而不是固定的字体目录(即使文件存在,VertX也不会从字体目录提供)

在这里输入图像描述

  router.route("/fonts/glyphicons-halflings-regular.woff2").handler { it.response().sendFile("glyphicons-halflings-regular.woff2") } router.route("/fonts/glyphicons-halflings-regular.woff").handler { it.response().sendFile("glyphicons-halflings-regular.woff") } router.route("/fonts/glyphicons-halflings-regular.ttf").handler { it.response().sendFile("glyphicons-halflings-regular.ttf") } router.route().handler(StaticHandler.create().setCachingEnabled(true)); 

Favicon可能被缓存,仍然在调查,favicon目前并不是那么重要。

 router.route("/favicon.ico").handler(FaviconHandler.create("favicon.ico")) 

favicon.ico的:

只需将favicon.ico文件直接移动到resources文件夹即可:

 /src/main/resources/favicon.ico 

或者改变你的FaviconHandler来传递路径和文件名:

 router.route().handler(FaviconHandler.create(FaviconHandler.create("webroot/favicon.ico"))) 

你的代码假设FaviconHandler也尊重FaviconHandler设置的webroot ,但是它没有。 这纯粹是StaticHandler一个属性,因此FaviconHandlerresources/查找资源,除非您指定相对路径。 当找不到资源时, 它使用getResourceAsStream("favicon.ico")的结果,该结果为null并崩溃。

如果您查看FaviconHandlerImpl的单元测试,您会看到他们将favicon.ico文件放在资源的根目录而不是webroot


WOFF文件:

至于你的字体文件,你在错误的地方看问题。 它与MIME类型无关。

更可能的是,你在事故中损坏了WOFF文件。 这可能发生在你用GIT提交它们时,它认为它们是文本文件,它打破了行结尾,从而破坏了它们。 或者你使用Maven Filter插件,它做了同样的,腐蚀他们。 或者你上传/下载他们通过FTP作为文本文件,同样的问题。

查看关于这个的其他帖子: https : //stackoverflow.com/a/33792610/3679676

您不指定您的图标路径,所以Vertx尝试找到默认路径:

  if (path == null) { icon = new Icon(Utils.readResourceToBuffer("favicon.ico")); } 

您的图标位于resources/webroot/favicon.ico ,但Vertx在resources/favicon.ico查找

因此,您可以指定FaviconHandler.create("webroot/favicon.ico")或将其移动到一个目录中。

关于WOFF文件,我无法重现这个问题,因为WOFF返回application/x-font-woff ,这似乎是正确的。