我正在尝试使用wai编写一个非常简单的“回声”webapp;所有我想要它做的是回复POST的数据(我真的不关心方法,但我正在使用curl和curl使用POST,所以这就是我想要的)。我的琐碎的Web服务器是这样的:
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”部分工作,然后我看到我的应用程序将整个请求主体打印到stdout,所以我知道curl正在正确地提交数据。我也将“Hello World”打印到curl stdout上,所以我知道卷曲的效果与我期望的一样。在将requestBody绑定到ResponseSource的地方,我一定做错了,但是我没有看到它。
答案 0 :(得分:1)
您正确使用conduit
,问题是您尝试获取的流式传输行为无法在HTTP上下文中可靠地工作。基本上,您希望在客户端发送请求正文时开始发送响应正文。这可能会导致死锁,因为客户端和服务器都可能陷入发送模式。为避免这种情况,Warp会在发送响应之前刷新请求正文,这就是请求正文在发送响应正文时显示为空的原因。
为了使回声行为正确,您需要严格使用请求正文然后将其发回。显然,如果存在大量请求主体,从内存使用的角度来看,这可能是有问题的,但这是HTTP的固有方面。如果你想要恒定的内存回声,我的建议是将请求体流式传输到一个文件,然后使用ResponseFile
作为响应体。