【问题标题】:Akka-http custom 404 pageAkka-http 自定义 404 页面
【发布时间】:2017-07-01 12:35:34
【问题描述】:

我想在 akka-http(高级 DSL)中创建一个自定义 404 页面。这基本上意味着:

  1. 从我的静态文件夹中返回一个页面(例如,resources/www/404.html)
  2. 将结果代码设置为 ResultCodes.NOT_FOUND

到目前为止我尝试了什么:

  1. getFromResource - 我可以返回实体,但我不知道如何覆盖响应的 HTTP 结果代码,因此我可以将其设置为“404”。
  2. complete() - 我可以返回正确的代码,但我需要手动读取 html 页面,并从头开始构建 HttpResponse。它最终可以工作,但有点麻烦。

我错过了什么吗?有没有更简单的方法返回页面并自定义结果代码?

【问题讨论】:

    标签: akka-http


    【解决方案1】:

    静态页面可以作为HttpResponseentity 返回。

    假设你有表单的一些功能

    def someFunctionThatCanFail() : Try[HttpResponse] = ???
    

    如果发生故障,您需要使用静态页面。您首先需要创建一个基于静态页面的Source

    import akka.stream.scaladsl._
    import akka.http.scaladsl.model.HttpEntity.Chunked
    
    def createStaticSource(fileName : String) = 
      FileIO
        .fromPath(Paths get fileName)
        .map(ChunkStreamPart.apply)
    
    def createChunkedSource(fileName : String) = 
      Chunked(ContentTypes.`text/html(UTF-8)`, createStaticSource(fileName))
    

    然后可以将此源放置在响应中:

    def staticResponse = 
      HttpResponse(status = StatusCodes.NotFound,
                   entity = createChunkedSource("resources/www/404.html"))
    

    剩下要做的就是要么返回函数的结果,如果它是有效的,或者在失败的情况下返回静态响应:

    val route = 
      get {
        complete(someFunctionThatCanFail() getOrElse staticResponse)
      }
    

    【讨论】:

    • @WillIAm 欢迎您。我同意这不像“一个班轮”那么简单,但我不明白这怎么可能。使用实体创建 404 响应与使用实体创建 400 响应的操作完全相同。模式有足够的分歧,我不认为图书馆可以大大提高冗长性。我已经更新了答案,让它更像一个 util 库函数,至少你只需要写一次......
    • 糟糕,我错误地删除了我之前的评论(但没有什么重要的,只是感谢并抱怨它不是很简单:)。顺便说一句,在您的代码中,我在 staticResponse = ... (expected Seq[HttpHeader], actual HttpEntity.Chunked)
    • 谢谢。我之所以说它需要更简单是因为不是每个人都使用 Scala。一直在尝试将上面的示例转换为使用 javadsl,并且没有通过 createChunkedSource 的实现
    • 我正在为一个新项目重新审视这个答案(再次感谢)。我发现应用程序打包在 jar 中时 fromPath 不起作用。这是正确的还是我有其他错误?如果它是正确的,我的替代方案是什么?
    • @WillIAm 在 jar 打包后,我肯定已将 fromPath 与外部文件一起使用。也许尝试将一个小测试文件捆绑到与 jar 一起打包的资源目录中。如果这样可行,那么至少您已经隔离了问题的根源......
    【解决方案2】:

    为了扩展 Ramon 的出色答案,这也适用于 jar 文件:

     def createChunkedSource(fileName : String): Chunked = {
        def createStaticSource(fileName : String) : Source[ChunkStreamPart, Any] = {
          val classLoader = getClass.getClassLoader
          StreamConverters.fromInputStream(() => classLoader.getResourceAsStream(fileName)).map(ChunkStreamPart.apply)
        }
        Chunked(ContentTypes.`text/html(UTF-8)`, createStaticSource(fileName))
      }
    

    【讨论】:

      猜你喜欢
      • 2018-11-16
      • 2010-11-04
      • 2012-10-26
      • 2011-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-01
      相关资源
      最近更新 更多