我在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表现得像这样?
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
如果不清楚,我想处理所有抛出的错误,因此我可以记录它们并显示自定义错误页面。 (当然,除了在记录和显示错误页面时抛出的错误)。指导将不胜感激。
答案 0 :(得分:0)
顺便说一句,我找到了答案。基本上它与延迟评估有关 - {Hampstack在内部开始将数据流传输到响应主体之前,Response
对象仅被评估为WHNF,此时将状态代码从200更改为500为时已晚
如果响应是视频流,这是正确的行为,因为在发送HTTP响应之前严格评估响应以确保它不包含任何undefined
值,在这种情况下将是不实用的。然而,对于 实用的已知小响应来说,明显不方便,严格评估以消除底值的任何可能性。此外,HTTP客户端(主要是浏览器)隐含地假设200响应代码意味着请求是成功的 - 并且仅在特定情况下(例如流视频)200响应以任何方式"不信任"并且消耗HTTP响应的代码更深入地查看它以确保它在处理并向最终用户显示之前格式良好且格式良好 - 实际上在我的问题中看到,因为浏览器显示空页面和网络选项卡显示200
没有内容,即使内部服务器错误很多。
Here是我对Happstack的拉取请求,它只是向Response
对象添加了一些类型类,因此可以在将其返回ServerPart
之前对其进行深入,严格的评估。单子。那个特定的PR有一个困难的历史(它曾经做过一些更大的范围),所以我可能关闭它并打开一个新的。如果是这样,那个应该被标记为已关闭,并且链接到新的。