在http-conduit中通过Maybe处理404

时间:2014-07-30 22:11:10

标签: haskell http-conduit

使用http-conduit我想下载实现以下语义的HTTP URL(导致IO (Maybe LB.ByteString)):

  1. 如果HTTP响应代码为2xx,则返回Just响应正文
  2. 如果HTTP响应代码为404,则返回Nothing
  3. 如果响应代码指示重定向,请按照标准的http-conduit设置
  4. 进行操作
  5. 对于任何其他响应代码,请抛出StatusCodeException
  6. 如果没有httpLbs以外的任何库及其依赖项,我怎样才能使用http-conduit

    注意:这个问题以Q& A形式回答,因此故意不显示研究工作。

1 个答案:

答案 0 :(得分:2)

可以使用与offical examples之一类似的自定义checkStatus来实现此目的。

如果响应状态代码是2xx或404,我们将声明传递的checkStatus200。如果它没有通过,它会调用默认的checkStatus函数来抛出相应的异常。

使用httpLbs使用Request致电checkStatus200后,我们可以检查状态代码并返回Just回复代码或Nothing

import Data.Conduit.Binary (sinkFile)
import Network.HTTP.Types.Status (Status(..))
import Network.HTTP.Conduit
import qualified Data.Conduit as C
import Network
import Data.Default (def)
import qualified Data.ByteString.Lazy as LB

-- | @checkStatus@ implementation that accepts 
--   2xx status codes and 404. Calls default implementation
--   on other status codes (i.e. throws exception)
checkStatus200 st@(Status sc _) rh cj =
    if (200 <= sc && sc < 300) || sc == 404
        then Nothing
        else (checkStatus def) st rh cj

-- | Download a HTTP link, returning @Nothing@ on 404 status code
downloadCatch404 :: String
                 -> IO (Maybe LB.ByteString)
downloadCatch404 url = withSocketsDo $ do
    request <- parseUrl url
    let request' = request { checkStatus = checkStatus200 }
    res <- withManager $ httpLbs request'
    let status =  statusCode . responseStatus $ res
    -- Return Nothing if status code == 404
    return $ if status == 404
        then Nothing
        else Just $ responseBody res