【发布时间】:2017-03-04 23:45:12
【问题描述】:
我正在尝试提供一个网站图标和一些字体。
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
当我直接访问该字体网址时,浏览器正尝试将字体下载为常规文件。
这似乎是一个潜在的解决方案,但我看到的不是我的图标,只是一个 16x16 的正方形,里面有扭曲的线条,字体仍在尝试下载,但仍然在浏览器控制台中显示错误。
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"))
【问题讨论】: