2012-01-27 13 views
6

Estoy tratando de descargar todos los archivos png contenidos en un archivo html. Tengo problemas para detectar excepciones de estado 404, en cambio, mi programa simplemente falla.¿Cómo puedo detectar una excepción de estado 404 lanzada por simpleHttp of Http.Conduit

Aquí es un poco de muestra para demostrar:

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) 

Mis "Oops" mensaje nunca grabados, en lugar aplicación se bloquea con:

StatusCodeException (Estado {statusCode = 404, StatusMessage = "No se ha encontrado "}) [(" Content-Type "," text/html; charset = UTF-8 "), (" X-Content-Type-Options "," nosniff "), (" Date "," Vie, 27 de enero " 2012 03:10:34 GMT "), (" Servidor "," sffe "), (" Content-Length "," 964 "), (" X-XSS-Protection "," 1; mode = block ")]

¿Qué estoy haciendo mal?

Actualización:

Siguiendo el consejo de Thoma, he cambiado de código para el siguiente fragmento y ahora tienen el control de excepciones adecuado en el lugar.

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) 

Respuesta

6

Probablemente deberías leer el Marlow paper on extensible exceptions. El catch original, exportado por Prelude y utilizado en el snip de código, solo funciona para IOError. El código de conducto http arroja excepciones de un tipo diferente, HttpException para ser exactos. (hay algo de tipado dinámico pasando por la clase Typeable, vea el artículo).

¿La solución? Use catch desde Control.Exception y solo capture los tipos de error que quiera manejar (o SomeException para todos ellos).

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) 
+0

Gracias, eso resolvió mi problema. Estoy de acuerdo con atrapar solo excepciones específicas (ese fue mi próximo paso, nunca llegué). –

8

Además de la respuesta de Thomas, se podría decir http-conduit no lanzar una excepción reemplazando el registro checkStatus de su tipo Request.

+0

hiciste mi día, como de costumbre (: –

Cuestiones relacionadas