在 Happstack 请求处理程序中捕获程序错误
Catch program errors in Happstack request handler
我在 Haskell 有点菜鸟,所以我不完全确定这是一个 Happstack 问题还是一个一般的 Haskell 问题。
这是我遇到的困难的一个例子。这段代码 "theoretically" 渲染了一些内容,但实际上抛出了一个错误:
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 returns 状态 500 并显示错误页面。为什么 Happstack 会这样?
ServerPart
monad 实现了 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
如果不清楚,我想处理所有抛出的错误,这样我就可以记录它们并显示自定义错误页面。 (当然,记录和显示错误页面时抛出的错误除外)。指导将不胜感激。
顺便说一句,我找到了答案。基本上它与惰性评估有关 - Response
对象仅评估为 WHNF 直到 Happstack 在内部开始将数据流式传输到响应主体之后,此时将状态代码从 200 更改为 500 为时已晚.
如果响应是视频流,这是正确的行为,因为在这种情况下,在发送 HTTP 响应之前严格评估响应以确保它不包含任何 undefined
值会很笨拙。然而,对于 是 实用的已知小响应来说,深入、严格地评估以消除任何可能的底部值显然是不方便的。此外,HTTP 客户端(主要是浏览器)隐含地假设 200 响应代码意味着请求成功 - 并且只有在特定情况下,例如流媒体视频,200 响应以任何方式 "not trusted" 和代码消耗HTTP 响应对其进行更深入的研究,以确保它在处理和显示给最终用户之前格式正确且格式正确 - 确实如我的问题中所见,因为浏览器显示一个空页面并且网络选项卡显示 200
没有任何内容,即使有很多内部服务器错误。
Here 是我针对 Happstack 的拉取请求,它只是将一些类型类添加到 Response
对象,以便可以在将其返回到 [=14 之前对其进行深入、严格的评估=] 单子。那个特定的 PR 有一段麻烦的历史(它曾经做一些范围更大的事情)所以我可能会关闭它并打开一个新的。如果是这样,那一个应该被标记为关闭并且有一个 link 到新的。
我在 Haskell 有点菜鸟,所以我不完全确定这是一个 Happstack 问题还是一个一般的 Haskell 问题。
这是我遇到的困难的一个例子。这段代码 "theoretically" 渲染了一些内容,但实际上抛出了一个错误:
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 returns 状态 500 并显示错误页面。为什么 Happstack 会这样?
ServerPart
monad 实现了 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
如果不清楚,我想处理所有抛出的错误,这样我就可以记录它们并显示自定义错误页面。 (当然,记录和显示错误页面时抛出的错误除外)。指导将不胜感激。
顺便说一句,我找到了答案。基本上它与惰性评估有关 - Response
对象仅评估为 WHNF 直到 Happstack 在内部开始将数据流式传输到响应主体之后,此时将状态代码从 200 更改为 500 为时已晚.
如果响应是视频流,这是正确的行为,因为在这种情况下,在发送 HTTP 响应之前严格评估响应以确保它不包含任何 undefined
值会很笨拙。然而,对于 是 实用的已知小响应来说,深入、严格地评估以消除任何可能的底部值显然是不方便的。此外,HTTP 客户端(主要是浏览器)隐含地假设 200 响应代码意味着请求成功 - 并且只有在特定情况下,例如流媒体视频,200 响应以任何方式 "not trusted" 和代码消耗HTTP 响应对其进行更深入的研究,以确保它在处理和显示给最终用户之前格式正确且格式正确 - 确实如我的问题中所见,因为浏览器显示一个空页面并且网络选项卡显示 200
没有任何内容,即使有很多内部服务器错误。
Here 是我针对 Happstack 的拉取请求,它只是将一些类型类添加到 Response
对象,以便可以在将其返回到 [=14 之前对其进行深入、严格的评估=] 单子。那个特定的 PR 有一段麻烦的历史(它曾经做一些范围更大的事情)所以我可能会关闭它并打开一个新的。如果是这样,那一个应该被标记为关闭并且有一个 link 到新的。