用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
和正常的html
, js
和css
文件服务正常,但字体无法服务。
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
一个属性,因此FaviconHandler
在resources/
查找资源,除非您指定相对路径。 当找不到资源时, 它使用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
,这似乎是正确的。