1

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

  1. 如果 HTTP 响应码是 2xx,则返回Just响应体
  2. 如果 HTTP 响应码是 404,则返回Nothing
  3. 如果响应代码指示重定向,请按照标准 http-conduit 设置进行操作
  4. 对于任何其他响应代码,抛出一个StatusCodeException.

httpLbs如果没有任何库http-conduit及其依赖项,我该如何做到这一点?

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

4

1 回答 1

2

这可以通过使用checkStatus类似于官方示例之一的自定义来实现。

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

httpLbs使用Requestusing调用后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
于 2014-07-30T22:11:10.430 回答