3

我是 Haskell 的菜鸟,所以我不完全确定这是 Happstack 问题还是一般 Haskell 问题。

这是我遇到的困难的一个例子。这段代码“理论上”渲染了一些内容,但实际上抛出了一个错误:

throwsError :: String
throwsError = fromJust Nothing

-- no error page
main :: IO ()
main = do
  simpleHTTP nullConf $ do
    decodeBody (defaultBodyPolicy "/tmp/" 4096 4096 4096)
    ok $ toResponse throwsError

此错误不会使整个程序崩溃。幸运的是,Happstack 可以捕获在处理请求时抛出的任何错误,就像 Web 服务器应该做的那样。但是,不幸的是,它不会向用户显示任何类型的错误页面。它以状态码 200 和空内容响应。

现在,如果我只是先输出错误字符串:

-- yes error page
main :: IO ()
main = do
  simpleHTTP nullConf $ do
    decodeBody (defaultBodyPolicy "/tmp/" 4096 4096 4096)
    lift $ putStrLn throwsError -- added this line
    ok $ toResponse throwsError

Happstack 返回状态 500 并显示错误页面。为什么 Happstack 会这样?

ServerPartmonad 实现了MonadThrow,所以我尝试导入Control.Monad.Catch (handle)和编写它,但它没有达到我的预期;它再次返回 200 没有内容:

showErrorPage :: SomeException -> ServerPart Response
showErrorPage _ = internalServerError $ toResponse "Error"

-- also no error page
main :: IO ()
main = do
  simpleHTTP nullConf $ handle showErrorPage $ do
    decodeBody (defaultBodyPolicy "/tmp/" 4096 4096 4096)
    ok $ toResponse throwsError

如果不清楚,我想处理所有抛出的错误,以便记录它们并显示自定义错误页面。(当然,记录和显示错误页面时抛出的错误除外)。指导将不胜感激。

4

1 回答 1

0

顺便说一句,我找到了答案。基本上它与惰性评估有关 -Response对象仅评估为 WHNF,直到 Happstack 内部开始将数据流式传输到响应正文之后,此时将状态代码从 200 更改为 500 为时已晚。

如果响应是视频流,则这是正确的行为,因为在这种情况下,在发送 HTTP 响应之前严格评估响应以确保它不包含任何undefined值将是笨拙的。但是,对于已知较小的响应,这显然是不方便的切实深入、严格评估,杜绝任何出现底值的可能性。此外,HTTP 客户端(主要是浏览器)隐含地假设 200 响应代码意味着请求成功 - 只有在特定情况下,例如流媒体视频,200 响应才以任何方式“不受信任”并且代码消耗HTTP 响应对其进行了更深入的研究,以确保在处理并将其显示给最终用户之前它的格式正确且格式正确 - 实际上正如我的问题中所见,因为浏览器显示一个空页面并且网络选项卡显示200没有内容,即使有很多内部服务器错误。

是我对 Happstack 的拉取请求,它只是向对象添加了一些类型类,以便可以在将其返回到monadResponse之前对其进行深入、严格的评估。ServerPart那个特定的 PR 有一段麻烦的历史(它曾经做过一些更大的事情),所以我可能会关闭它并打开一个新的。如果是这样,则应将其标记为已关闭,并具有指向新的链接。

于 2018-04-27T05:48:04.957 回答