使用http-conduit
,我想下载一个实现以下语义的HTTP URL(导致IO (Maybe LB.ByteString)
):
- 如果HTTP响应码为2xx,返回
Just
响应体 - 如果HTTP响应码是404,返回
Nothing
- 如果响应代码指示重定向,则按照标准http-conduit设置执行
- 对于任何其他响应码,抛出
StatusCodeException
。
我怎么能做到这一点使用httpLbs
没有任何库超出http-conduit
和它的依赖关系?
注意:这个问题是在Q&A表格中回答的,因此没有显示出研究的努力。
这可以通过使用与官方示例类似的自定义checkStatus
实现。
如果响应状态码是2xx或404,我们将声明checkStatus200
通过。如果没有通过,它调用默认的checkStatus
函数来抛出相应的异常。
在使用checkStatus200
调用Request
调用httpLbs
之后,我们可以检查状态码并返回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