1

也许做事的方式很愚蠢,但就是这样。我想将 HTTP 请求发送/接收与处理响应分开。

import Pipes
import qualified Pipes.HTTP as HTTP
import Pipes.Core
import qualified Pipes.ByteString as PB
import Network.Socket (withSocketsDo)

fetch m url = do
  req <- lift $ HTTP.parseUrl url
  resp <- lift $ HTTP.withHTTP req m return
  url' <- respond $ HTTP.responseBody resp
  fetch m url'

client :: Client String (Producer PB.ByteString IO ()) IO ()
client = do
          b <- request "http://www.google.com"
          lift $ runEffect $ b >-> PB.stdout

main = withSocketsDo $ HTTP.withManager HTTP.tlsManagerSettings $ \m ->
     runEffect $ fetch m +>> client

似乎合法。但是我得到了部分响应打印和“Network.Socket.ByteString.recv:失败(未知错误)”。我需要做些什么不同的事情?

4

1 回答 1

3

错误是这部分:

HTTP.withHTTP req m return

有一个约定(不是由类型强制执行的),当函数以单词开头时with,您不允许让它分配的资源从它所包含的块中逃逸。原因是这些withXXX函数在块完成时处理资源,因此资源在该点之后无效。

所以发生的事情是您尝试return了来自withHTTP块的响应,但是通过下一行代码,响应已经被处理掉了。解决方案是使用pipes-safe,它允许您在管道内使用Pipes.Safe.bracket. 您所要做的就是提供一个打开和关闭操作:

fetch m url = do
    req  <- lift $ HTTP.parseUrl url
    url' <- bracket openSomething closeSomething $ \resp -> do
        respond $ HTTP.responseBody resp
    fetch m url'

这将确保resp在完成之前不会发布respond

于 2014-12-07T03:04:55.190 回答