[英]http-conduit, snap and lazy IO
我有兩個使用snap框架使用json api的http服務器
我的第一個原型包含一個與此示例處理程序相似的處理程序
import Data.ByteString (ByteString)
import Data.ByteString.Char8 as B (unwords, putStrLn)
import Data.ByteString.Lazy.Char8 as L (putStrLn)
import Control.Monad.IO.Class (liftIO)
import Data.Monoid ((<>))
import Snap.Core (getParam, modifyResponse, setHeader, writeLBS)
import Network.HTTP.Conduit
import Network.HTTP.Client (defaultManagerSettings)
exampleHandler :: AppHandler ()
exampleHandler = do resp <- liftIO
$ do L.putStrLn "Begin request ..."
initReq <- parseUrl "http://localhost:8001/api"
manager <- newManager defaultManagerSettings
let req = initReq { method = "GET"
, proxy = Nothing}
r <- httpLbs req manager
L.putStrLn "... finished request."
return $ responseBody r
liftIO . L.putStrLn $ "resp: " <> resp
modifyResponse $ setHeader "Content-Type" "application/json"
writeLBS $ "{ \"data\": \""<> resp <>"\" }"
如果我發出ajax請求,則發送和接收響應-當服務器在控制台上寫入resp: testdata
時,我會看到此消息,但使用writeLBS
發送給瀏覽器的響應卻沒有。 現在,如果我將最后一行更改為
writeLBS $ "{ \"data\": \""<> "something fixed" <>"\" }"
一切都像魅力。 我認為我正在遇到惰性IO的陷阱之一,但是我不知道該如何解決。
我還嘗試了一些不帶liftIO
變體,但將liftIO
放在必要的地方。
根據@MichaelSnoyman的評論,我對writeLBS
進行了一些研究,並試圖
modifyResponse $ setBufferingMode False
. setHeader "Content-Type" "application/json"
writeLBS resp
正如我認為緩沖可能是問題-不,不是
此外,我嘗試顯式編寫一個setResponseBody
let bb = enumBuilder . fromLazyByteString $ "{ \"data\": \""<> resp <>"\" }"
modifyResponse $ setBufferingMode False
. setHeader "Content-Type" "application/json"
. setResponseBody bb
這也顯示沒有成功。
我已經解決了這個問題-實際上,這是javascript獲取手寫json的問題(自我注意:永遠不要再這樣做了)。 在輸入數據的末尾有一個不間斷的空格,該空格未正確編碼,而且由於我是JS的新手,所以我沒有從錯誤消息中得到該空格。
中間解決方案是添加urlEncode
並制作一個嚴格的ByteString
let respB = urlEncode . L.toStrict $ C.responseBody resp
modifyResponse $ setBufferingMode False
. setHeader "Content-Type" "application/json"
writeBS $ "{ \"data\": \"" <> respB <> "\" }"
當然,您必須相應地更改進口。
長期的解決方案是:編寫一個正確的from/toJSON
實例,然后讓該庫處理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.