10

我正在编写将通过 HTTP 下载一些文件的应用程序。到目前为止,我一直在使用以下代码片段来下载页面正文:

import network.HTTP
simpleHTTP (getRequest "http://www.haskell.org/") >>= getResponseBody

它工作正常,但无法通过 HTTPS 协议建立连接。所以为了解决这个问题,我已经切换到 HTTP-Conduit,现在我正在使用以下代码:

simpleHttp' :: Manager -> String -> IO (C.Response LBS.ByteString)
simpleHttp' manager url = do
     request <- parseUrl url
     runResourceT $ httpLbs request manager

它可以连接到 HTTPS,但出现了新的令人沮丧的问题。大约每五次连接失败,但有例外:

getpics.hs: FailedConnectionException "i.imgur.com" 80

我确信这是 HTTP-Conduit 问题,因为 network.HTTP 在同一组页面(不包括 https 页面)上运行良好。

有没有人遇到过这样的问题并且知道解决方案或更好的解决方案(而且很简单,因为这是一个简单的任务,不应该花费超过几行代码)替代 Conduit 库?

4

1 回答 1

2

一种简单的替代方法是使用curl包。它支持 HTTP、HTTPS 和许多其他替代协议,以及许多自定义其行为的选项。代价是引入了对libcurl的外部依赖,这是构建软件包所必需的。

例子:

import Network.Curl

main :: IO ()
main = do
  let addr = "https://google.com/" 
  -- Explicit type annotation is required for calls to curlGetresponse_.
  -- Use ByteString instead of String for higher performance:
  r <- curlGetResponse_ addr [] :: IO (CurlResponse_ [(String,String)] String)

  print $ respHeaders r
  putStr $ respBody r

更新:我试图复制你的问题,但一切都对我有用。您能否发布一个简短的、自包含的、可编译的示例来演示该问题?我的代码:

import Control.Monad
import qualified Data.Conduit as C
import qualified Data.ByteString.Lazy as LBS
import Network.HTTP.Conduit

simpleHttp'' :: String -> Manager -> C.ResourceT IO (Response LBS.ByteString)
simpleHttp'' url manager = do
     request <- parseUrl url
     httpLbs request manager

main :: IO ()
main = do
  let url = "http://i.imgur.com/"
      count = 100
  rs <- withManager $ \m -> replicateM count (simpleHttp'' url m)
  mapM_ (print . responseStatus) $ rs
于 2013-12-21T19:17:29.340 回答