【问题标题】:Encoding JSON as Base64 Before HTTP POSTing It (in Haskell)在 HTTP POST 之前将 JSON 编码为 Base64(在 Haskell 中)
【发布时间】:2017-07-02 02:11:30
【问题描述】:

问题:我正在尝试将一些 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),但出现类型错误。那么对于这个 HTTP POST,我该如何将 JSON 编码为 Base64 呢?

【问题讨论】:

    标签: json http haskell


    【解决方案1】:

    B64.encode here 是一个从 strict ByteString 到 strict ByteString 的函数(如果您只是浏览,则需要将鼠标悬停在黑线鳕中的类型名称上才能看到),而 @987654325 @ 返回一个惰性字节串(来自 Data.ByteString.Lazy 模块)。尽管名称相同,但它们是两种不同的类型。

    您可能必须执行以下操作:

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

    【讨论】:

    • 这个编译没有错误;但是,我的 JSON POST 仍然没有被主机接受。目前尚不清楚它是否与这个问题或其他完全有关。
    • 问题是 JSON 没有附加到端点 URL 的 dataquery 参数,因此它显示为 http://api.mixpanel.com/track/?data=&lt;...encoded JSON here...&gt;。我正在阅读文档以解决该问题,但我认为您解决了 B64 编码问题。
    • 啊,所以你不希望它在帖子的正文中,而是在查询字符串中
    【解决方案2】:

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

    首先,如果(现在看起来)您要将其放入查询字符串中,您需要确保您不只是使用 base64 编码的字节串,而是使用 base64 url -编码字节串。所以不要使用Data.Bytestring.Base64(与jberryman 链接),而是使用Data.Bytestring.Base64.URLhere)。

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

    该函数具有签名:

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

    所以如果你是 base64 编码的字节串是这样构建的

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-31
      • 1970-01-01
      • 1970-01-01
      • 2014-07-13
      • 1970-01-01
      • 2014-11-14
      • 1970-01-01
      • 2012-10-18
      相关资源
      最近更新 更多