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: failed (Unknown error)」が表示されます。他に何をする必要がありますか?

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 に答える