2012-01-27 9 views
6

Sto provando a scaricare tutti i file png contenuti in un file html. Ho problemi ad individuare le 404 eccezioni di stato, invece il mio programma si blocca.Come posso rilevare un'eccezione di stato 404 generata da Http.Http di Http.Conduit

Ecco qualche esempio per dimostrare:

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) 

I miei "oops" messaggio mai stampe, invece applicazione si blocca con:

StatusCodeException (Stato {statusCode = 404, statusMessage = "non trovato "}) [(" Content-Type "," text/html; charset = UTF-8 "), (" X-Content-Type-Options "," nosniff "), (" Data "," Ven, 27 gen 2012 03:10:34 GMT "), (" Server "," sffe "), (" Content-Length "," 964 "), (" X-XSS-Protection "," 1; mode = block ")]

Cosa sto sbagliando?

Aggiornamento:

Seguendo il consiglio di Thoma, ho cambiato il mio codice al seguente frammento e ora hanno una corretta gestione delle eccezioni in atto.

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) 

risposta

6

Probabilmente si dovrebbe leggere il Marlow paper on extensible exceptions. L'originale catch, esportato da Prelude e utilizzato nel codice snipt, funziona solo per IOError. Il codice http-conduit genera eccezioni di un tipo diverso, HttpException per l'esattezza. (c'è un po 'di digitazione dinamica in corso tramite la classe Typeable, vedi la carta).

La soluzione? Usa catch da Control.Exception e prendi solo i tipi di errore che vuoi gestire (o SomeException per tutti loro).

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

Grazie, questo ha risolto il mio problema. Sono d'accordo nel rilevare solo eccezioni specifiche (questo era il mio prossimo passo, non ci sono mai arrivato). –

8

Oltre alla risposta di Thomas, si potrebbe dire http-conduit non un'eccezione sovrascrivendo il record checkStatus del vostro tipo Request.

+0

hai fatto la mia giornata, come al solito (: –