Как я могу поймать 404 исключение состояния, выдаваемое по простой Http.Conduit - PullRequest
6 голосов
/ 27 января 2012

Я пытаюсь загрузить все файлы png, содержащиеся в html-файле. У меня проблемы с перехватом 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)

Мое сообщение "упс" никогда не печатается, вместо этого приложение вылетает с:

StatusCodeException (Status {statusCode = 404, statusMessage = "Not Found"}) [("Content-Type", "text / html; charset = UTF-8"), ("X-Content-Type-Options" " , "nosniff"), ("Дата", "Пт, 27 января 2012 03:10:34 GMT"), ("Сервер", "sffe"), ("Длина контента", "964"), (" X-XSS-Protection "," 1; mode = block ")]

Что я делаю не так?

Обновление:

Следуя совету Тома, я изменил свой код на следующий фрагмент, и теперь у меня есть правильная обработка исключений.

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)

Ответы [ 2 ]

8 голосов
/ 27 января 2012

В дополнение к ответу Томаса, вы можете сказать http-conduit, что не следует выдавать исключение, переопределив запись checkStatus вашего типа Request.

6 голосов
/ 27 января 2012

Вам, вероятно, следует прочитать статью Marlow о расширяемых исключениях .Оригинальный catch, экспортированный Prelude и используемый в вашем фрагменте кода, работает только для IOError.Код http-проводника генерирует исключения другого типа, если быть точным, HttpException .(в классе Typeable происходит некоторая динамическая типизация, см. статью).

Решение?Используйте catch из Control.Exception и перехватывайте только те типы ошибок, которые вы хотите обработать (или 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)
...