3

我正在尝试使用 wai 编写一个非常微不足道的“回声”网络应用程序;我想要它做的就是回复发布给它的数据(我真的不关心该方法,但我正在使用 curl 并且 curl 正在使用 POST,所以这就是我想要的)。我的微不足道的网络服务器是这样的:

import Network.Wai
import Network.HTTP.Types (status200)
import Network.Wai.Handler.Warp (run)
import Control.Monad.Trans ( liftIO )
import Blaze.ByteString.Builder.ByteString (fromByteString)
import qualified Data.Conduit.List as CondList
import Data.Conduit ( ($$), ($=), Flush(Chunk) )

application req = do
  let src = requestBody req $= CondList.map (Chunk ∘ fromByteString)
  return $ ResponseSource status200 [("Content-Type", "text/plain")] src

main = run 3000 application

我期望这样做基本上是将请求正文与响应正文联系起来,这样当我运行curl --data @/usr/share/dict/words localhost:3000; 它会向我吐出我的话。相反,它给出了一个空的身体。使用“-v”运行 curl 表明我的应用正在回复“200 OK”并且没有数据。我不确定我在这里做错了什么。

如果我用这个替换应用程序功能:

_ ← requestBody req $$ CondList.mapM_ (liftIO ∘ print)
return $ responseLBS status200 [("Content-Type", "text/plain")] "Hello world\n"

并添加一个 OverloadedStrings 杂注以允许“Hello World”部分工作,然后我确实看到我的应用程序将整个请求正文打印到标准输出,所以我知道 curl 正在正确提交数据。我还将“Hello World”打印到 curl 标准输出,所以我知道 curl 按我的预期工作。在将 requestBody 绑定到 ResponseSource 的地方,我一定做错了,但我没有看到。

4

1 回答 1

1

您正确使用conduit,问题是您尝试获得的流式传输行为无法在 HTTP 上下文中可靠地工作。本质上,您希望在客户端发送请求正文时开始发送响应正文。这可能导致死锁,因为客户端和服务器都可能卡在发送模式。为了避免这种情况,Warp 在发送响应之前刷新请求正文,这就是为什么在发送响应正文时请求正文显示为空的原因。

为了使回显行为正确,您需要严格使用请求正文,然后将其发回。显然,如果请求体很大,从内存使用的角度来看,这可能会出现问题,但这是 HTTP 的固有方面。如果您想要持续的内存回显,我的建议是将请求正文流式传输到文件,然后ResponseFile用于响应正文。

于 2012-05-30T01:28:12.847 回答