Haskell http管道、快照和惰性IO

Haskell http管道、快照和惰性IO,haskell,haskell-snap-framework,http-conduit,lazy-io,Haskell,Haskell Snap Framework,Http Conduit,Lazy Io,我有两个http服务器使用snap框架使用json api 我的第一个原型包含一个类似于这个示例处理程序的处理程序 import Data.ByteString (ByteString) import Data.ByteString.Char8 as B (unwords, putStrLn) import Data.ByteString.Lazy.Char8 as L (putStrLn) import Contr

我有两个http服务器使用snap框架使用json api

我的第一个原型包含一个类似于这个示例处理程序的处理程序

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 <>"\" }"
每件事都很有魅力。我想我遇到了懒惰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
让bb=enumBuilder。fromLazyByteString$“{\'数据\”:\“resp”\“}”
modifyResponse$setBufferingMode错误
. setHeader“内容类型”“应用程序/json”
. setResponseBody bb

这也没有成功。

我已经解决了这个问题-实际上是javascript获取手写json的问题(请注意:不要再这样做了)。在输入数据的末尾有一个未正确编码的非中断空格,我是JS的新手,所以没有从错误消息中得到它

中间解决方案是添加
urlEncode
,并通过testring

               let respB = urlEncode . L.toStrict $ C.responseBody resp
               modifyResponse $ setBufferingMode False
                              . setHeader "Content-Type" "application/json"
               writeBS $ "{ \"data\": \"" <> respB <> "\" }"
让respB=urlEncode。L.toStrict$C.ResponseBy resp
modifyResponse$setBufferingMode错误
. setHeader“内容类型”“应用程序/json”
writeBS$“{\'数据\”:\“respB”\“}”
当然,您必须相应地更改导入


长期的解决方案是:编写一个适当的
from/toJSON
实例,让库来处理这个问题。

我没有任何关于快照方面可能发生的事情的细节,但只是澄清一下
httpLbs
不执行惰性I/O。它严格地执行自己的操作,并且仅使用惰性ByteString以提高内存使用率(有关详细信息,请参阅文档)。关于
writeLBS$L.pack$“{\”data\”:\“++resp++”}”
?@Sigrlami resp已经是惰性
ByteString
。因此,
L.pack
将引入类型错误-我使用的是“OverloadedString”。@MichaelSnoyman感谢您确认
httpLbs
不太可能是罪魁祸首-我对
writeLBS
进行了一些研究,请参见编辑
               let respB = urlEncode . L.toStrict $ C.responseBody resp
               modifyResponse $ setBufferingMode False
                              . setHeader "Content-Type" "application/json"
               writeBS $ "{ \"data\": \"" <> respB <> "\" }"