3

wai を使用して、非常に単純な「エコー」Web アプリケーションを作成しようとしています。私がやりたいのは、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 がデータを適切に送信していることがわかります。また、curl stdout に「Hello World」が出力されるので、curl が期待どおりに機能することがわかります。requestBody を ResponseSource に結び付けているところで何か間違ったことをしているに違いありませんが、表示されません。

4

1 に答える 1

1

を正しく使用しています。conduit問題は、取得しようとしているストリーミング動作が HTTP のコンテキストで確実に機能しないことです。基本的に、クライアントがリクエスト本文を送信している間に、レスポンス本文の送信を開始します。これにより、クライアントとサーバーの両方が送信モードでスタックする可能性があるため、デッドロックが発生する可能性があります。これを回避するために、Warp は応答を送信する前に要求本文をフラッシュします。これが、応答本文が送信された時点で要求本文が空に見える理由です。

エコーの動作を正しくするには、リクエストの本文を厳密に消費してから送り返す必要があります。明らかに、これは大きなリクエスト ボディがある場合にメモリ使用量の観点から問題になる可能性がありますが、これは HTTP 固有の側面です。一定のメモリ エコーが必要な場合は、要求本文をファイルにストリーミングしてからResponseFile、応答本文に使用することをお勧めします。

于 2012-05-30T01:28:12.847 に答える