在HTTP POST之前将JSON编码为Base64(在Haskell中)

时间:2017-06-30 21:04:47

标签: json http haskell

问题:我正在尝试将一些JSON发布到仅接受Base64编码的HTTP端点。

代码示例:以下是无需 Base64编码即可成功发布的代码示例:

{-# LANGUAGE OverloadedStrings #-}

module Lib where

import           Data.Aeson                 (encode, object, (.=))
import qualified Data.ByteString.Lazy.Char8 as L8
import           Network.HTTP.Client
import           Network.HTTP.Client.TLS
import           Network.HTTP.Types.Status  (statusCode)
import qualified Data.ByteString.Base64 as B64

postJSON :: IO ()
postJSON = do
    manager <- newManager tlsManagerSettings

    -- Nested JSON object to POST:
    let requestObject = object
            [ "event" .= ("App launched." :: String)
            , "properties"  .=  object [  "distinct_id" .= ("user" :: String)
                                       ,  "token"       .= ("f793bae9548d8e123cef251fd81df487" :: String)
                                       ]
            ]  
    initialRequest <- parseRequest "http://api.mixpanel.com/track"
    let request = initialRequest
            { method = "POST"
            , requestBody = RequestBodyLBS $ encode requestObject
            , requestHeaders =
                [ ("Content-Type", "application/json; charset=utf-8")
                ]
            }

    response <- httpLbs request manager
    putStrLn $ "The status code was: "
            ++ show (statusCode $ responseStatus response)
    L8.putStrLn $ responseBody response

尝试:为了将JSON发送为Base64编码,我尝试将requestBody = RequestBodyLBS $ encode requestObject替换为requestBody = RequestBodyLBS $ Data.Bytestring.Base64.encode (encode requestObject),但是我收到了类型错误。那么如何将JSON编码为这个HTTP POST的Base64?

2 个答案:

答案 0 :(得分:3)

B64.encode here是一个从严格ByteString到严格ByteString的函数(您需要将鼠标悬停在黑线鳕的类型名称上,以查看此内容你只是在浏览),而Aeson.encode返回一个懒惰的字节串(来自Data.ByteString.Lazy模块)。这些是两种不同的类型,尽管它们具有相同的名称。

您可能需要执行以下操作:

   ...
   requestBody = RequestBodyLBS $ L8.fromStrict $ Data.Bytestring.Base64.encode (L8.toStrict $ encode requestObject)

答案 1 :(得分:2)

我有两件事要添加到jberryman的答案中。

首先,如果(现在看来)你将把它放在一个查询字符串中,你需要确保你不只是使用base64编码的字节串,而是使用base64 url -encoded bytestring。因此,请勿使用Data.Bytestring.Base64(与jberryman相关联),而应使用Data.Bytestring.Base64.URLhere)。

其次,虽然他在Base64编码部分指出了正确的方向,但似乎你仍然在设置查询字符串。为此,您应该查看您已使用的setQueryString库中的http-client函数(链接here)。

该功能有签名:

setQueryString :: [(ByteString, Maybe ByteString)] -> Request -> Request

所以如果你是base64编码的bytestring就像这样构建

let urlEncodedBytestring = Data.Bytestring.Base64.URL.encode . L8.toStrict $ encode requestObject

如果您正在尝试在请求的查询字符串中设置data键,那么您可能需要:

let requestWithQueryStringSet = setQueryString [("data", (Just urlEncodedBytestring))] request