如何捕获 Http.Conduit 的 simpleHttp 抛出的 404 状态异常

发布于 2024-12-29 15:41:02 字数 1479 浏览 2 评论 0原文

我正在尝试下载 html 文件中包含的所有 png 文件。 不过,我在捕获 404 状态异常时遇到了麻烦,相反,我的程序只是崩溃了。

下面是一些示例来演示:

import Network.HTTP.Conduit
import qualified Data.ByteString.Lazy as L

main = do
    let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png"    
    imgData <- (simpleHttp badUrl) `catch` statusExceptionHandler  
    L.writeFile "my.png" imgData

statusExceptionHandler ::  t -> IO L.ByteString
statusExceptionHandler e = (putStrLn "oops") >> (return L.empty)

我的“oops”消息永远不会打印,而是应用程序崩溃:

StatusCodeException(状态{statusCode = 404,statusMessage =“未找到”})[(“Content-Type”,“text/html;charset = UTF-8”),(“X-Content-Type-Options” ,"nosniff"),("日期","2012 年 1 月 27 日星期五 03:10:34 GMT"),("服务器","sffe"),("内容长度","964"),("X-XSS-保护","1; mode=block")]

我做错了什么?

更新:

按照 Thoma 的建议,我将代码更改为以下代码片段,现在已经有了适当的异常处理。

main = do
    let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png"    
    imgData <- (simpleHttp badUrl) `X.catch` statusExceptionHandler  
    case imgData of x | x == L.empty -> return () 
                      | otherwise    -> L.writeFile "my.png" imgData

statusExceptionHandler ::  HttpException -> IO L.ByteString
statusExceptionHandler (StatusCodeException status headers) = 
    putStr "An error occured during download: "
    >> (putStrLn $ show status)
    >> (return L.empty)

I'm trying to download all png files contained in an html file.
I have trouble catching 404 status exceptions though, instead my program just crashes.

Here is some sample to demonstrate:

import Network.HTTP.Conduit
import qualified Data.ByteString.Lazy as L

main = do
    let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png"    
    imgData <- (simpleHttp badUrl) `catch` statusExceptionHandler  
    L.writeFile "my.png" imgData

statusExceptionHandler ::  t -> IO L.ByteString
statusExceptionHandler e = (putStrLn "oops") >> (return L.empty)

My "oops" message never prints, instead app crashes with:

StatusCodeException (Status {statusCode = 404, statusMessage = "Not Found"}) [("Content-Type","text/html; charset=UTF-8"),("X-Content-Type-Options","nosniff"),("Date","Fri, 27 Jan 2012 03:10:34 GMT"),("Server","sffe"),("Content-Length","964"),("X-XSS-Protection","1; mode=block")]

What am I doing wrong?

Update:

Following Thoma's advice, I changed my code to the following snippet and now have proper exception handling in place.

main = do
    let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png"    
    imgData <- (simpleHttp badUrl) `X.catch` statusExceptionHandler  
    case imgData of x | x == L.empty -> return () 
                      | otherwise    -> L.writeFile "my.png" imgData

statusExceptionHandler ::  HttpException -> IO L.ByteString
statusExceptionHandler (StatusCodeException status headers) = 
    putStr "An error occured during download: "
    >> (putStrLn $ show status)
    >> (return L.empty)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夕色琉璃 2025-01-05 15:41:02

您可能应该阅读关于可扩展异常的马洛论文。原始 catch,由 Prelude 导出并在代码片段中使用,仅适用于 IOError。 http-conduit 代码抛出不同类型的异常,HttpException 。 (通过 Typeable 类进行一些动态类型,请参阅论文)。

解决方案是什么?使用 Control.Exception 中的 catch 和只捕获您想要处理的错误类型(或所有错误类型的 SomeException )。

import Network.HTTP.Conduit
import qualified Data.ByteString.Lazy as L
import Control.Exception as X

main = do
    let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png"
    imgData <- (simpleHttp badUrl) `X.catch` statusExceptionHandler
        L.writeFile "my.png" imgData

statusExceptionHandler ::  SomeException -> IO L.ByteString
statusExceptionHandler e = (putStrLn "oops") >> (return L.empty)

You should probably read the Marlow paper on extensible exceptions. The original catch, exported by Prelude and used in your code snipt, only works for IOError's. The http-conduit code is throwing exceptions of a different type, HttpException to be exact. (there is some dynamic typing going on via the Typeable class, see the paper).

The solution? Use catch from Control.Exception and only catch the error types you want to handle (or SomeException for all of them).

import Network.HTTP.Conduit
import qualified Data.ByteString.Lazy as L
import Control.Exception as X

main = do
    let badUrl = "http://www.google.com/intl/en_com/images/srpr/WRONG.png"
    imgData <- (simpleHttp badUrl) `X.catch` statusExceptionHandler
        L.writeFile "my.png" imgData

statusExceptionHandler ::  SomeException -> IO L.ByteString
statusExceptionHandler e = (putStrLn "oops") >> (return L.empty)
り繁华旳梦境 2025-01-05 15:41:02

除了 Thomas 的回答之外,您还可以通过覆盖 Request 类型的 checkStatus 记录来告诉 http-conduit 不要抛出异常。

In addition to Thomas's answer, you could tell http-conduit not to throw an exception by overriding the checkStatus record of your Request type.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文