简体   繁体   English

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

[英]Encoding JSON as Base64 Before HTTP POSTing It (in Haskell)

Problem: I am attempting to POST some JSON to an HTTP endpoint that only accepts Base64 encoding . 问题:我正在尝试将一些JSON发布到仅接受Base64编码的HTTP端点。

Code Sample: Here is a code sample which successfully posts without Base64 encoding: 代码示例:以下是无需使用 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

Attempt: In order to send the JSON as Base64 encoded, I tried replacing requestBody = RequestBodyLBS $ encode requestObject with requestBody = RequestBodyLBS $ Data.Bytestring.Base64.encode (encode requestObject) , but I get a type error. 尝试:为了以Base64编码形式发送JSON,我尝试用requestBody = RequestBodyLBS $ Data.Bytestring.Base64.encode (encode requestObject)替换requestBody = RequestBodyLBS $ encode requestObject ,但是出现类型错误。 So how do I encode the JSON as Base64 for this HTTP POST? 那么,如何为此HTTP POST将JSON编码为Base64?

B64.encode here is a function from strict ByteString to strict ByteString (you'll need to hover over the type name in the haddocks to see this if you're just browsing), while Aeson.encode returns a lazy bytestring (from the Data.ByteString.Lazy module). B64.encode 这里是从严格的功能ByteString ,以严格ByteString (你需要将鼠标悬停在类型名称的黑线鳕,看看这个,如果你只是浏览),而Aeson.encode返回一个懒惰的字节串(从Data.ByteString.Lazy模块)。 These are two distinct types although they have the same name. 尽管它们具有相同的名称,但它们是两种不同的类型。

You probably have to do something like: 您可能需要执行以下操作:

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

I have two things to add to jberryman's answer. 我要在jberryman的答案中添加两件事。

First, if (as it now appears) you're going to be putting this in a query string, you need to make sure you don't just use a base64 encoded bytestring, but instead use a base64 url-encoded bytestring. 首先,如果(要显示出来)将其放入查询字符串中,则需要确保您不仅使用base64编码的字节串,还使用base64 url编码的字节串。 So don't use Data.Bytestring.Base64 (as jberryman linked to), but rather Data.Bytestring.Base64.URL ( here ). 因此,请勿使用Data.Bytestring.Base64 (与jberryman链接),而应使用Data.Bytestring.Base64.URL此处 )。

Second, while he pointed you in the right direction on the Base64 encoding part, it seems you're still hung up on setting the querystring. 其次,尽管他在Base64编码部分为您指明了正确的方向,但似乎您仍然挂在设置查询字符串上。 For that, you should check out the setQueryString function in the http-client library you're already using (link here ). 为此,您应该在已经使用的http-client库中setQueryString函数( 在此处链接)。

That function has the signature: 该函数具有签名:

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

So if you're base64 encoded bytestring is built like this 因此,如果您是base64编码的字节串,将像这样构建

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

and if you're attemtping to set the data key in the querystring of your request, then you'll probably want: 并且如果您打算在请求的查询字符串中设置data键,那么您可能需要:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM