也许是一种愚蠢的做事方式,但在这里。我想分割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:failed(未知错误)”。我需要做些什么不同的事情?
答案 0 :(得分: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
完成后才会发布。