haskell - wai 的意外管道行为

标签 haskell conduit haskell-wai

我正在尝试使用 wai 编写一个非常简单的“echo”网络应用程序;我想要它做的就是回复发布给它的数据(我真的不关心该方法,但我使用的是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;它会把我的话吐回给我。相反,它给出了一个空的 body 。使用“-v”运行curl 显示我的应用程序正在回复“200 OK”并且没有数据。我不确定我在这里做错了什么。

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

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

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

最佳答案

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

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

关于haskell - wai 的意外管道行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10807824/

相关文章:

haskell - cabal 安装 hoogle 错误 - BuilderResponse 丢失

list - Haskell 自引用列表终止

haskell - 将 http-conduit 连接到 xml-conduit

haskell - 表现出奇怪的行为

haskell - 网络斯科蒂 : file not found while serving static files

haskell - 在 Haskell map 上求和

Haskell - 与数据类型匹配的模式

haskell - 使用 Haskell 的 zip-conduit 从 zip 存档中的文件中读取行

haskell - 在没有 "IO"的情况下在 WAI 中使用请求参数会导致问题

haskell - 用仆人/围服务静态文件