似乎bytestring
不是aeson
中的可序列化实例,根据aeson github tracker
: ticket1,ticket2下的这些门票,这可能是明智之举。
那么,在aeson
中序列化/反序列化二进制对象的好方法是什么呢?这是MDN
似乎建议用于序列化二进制对象的内容:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data。
更新
查看JSON
source code,我看到Word8
是一个有效的实例。那么,最好是从Javascript(Uint8Array
)发送Vector
Word8
的bytearray吗?
答案 0 :(得分:2)
由于你要求一个关于base64编码的例子,你的数据要通过JSON发送,我已经提出了一个粗略的例子:
{-# LANGUAGE OverloadedStrings #-}
module Main(main) where
import qualified Control.Applicative as App
import qualified Data.Aeson as A
import Data.Aeson.Types
import Data.ByteString
import qualified Data.ByteString.Lazy as LB
import Data.ByteString.Base64
import Data.Maybe (fromMaybe)
import Data.Text
import Data.Text.Encoding
data MyObject = MyObject { objectName :: Text, objectData :: ByteString } deriving (Eq)
instance FromJSON ByteString where
parseJSON (String t) = pure $ (either (const "") id . decode . encodeUtf8) t
parseJSON _ = App.empty
instance ToJSON ByteString where
toJSON = String . decodeUtf8 . encode
instance FromJSON MyObject where
parseJSON (Object v) = MyObject <$> v .: "name" <*> v .: "data"
parseJSON _ = App.empty
instance ToJSON MyObject where
toJSON obj = object [ "name" .= objectName obj, "data" .= objectData obj ]
exampleObject :: MyObject
exampleObject = MyObject "example" "\x01\x02\x03\x04\x05"
exampleJson :: LB.ByteString
exampleJson = "{\"data\":\"AQIDBAU=\",\"name\":\"example\"}"
main :: IO ()
main = do
print $ A.encode exampleObject
print $ exampleObject == fromMaybe (MyObject "fail" "") (A.decode exampleJson)
哪个应产生以下输出:
"{\"data\":\"AQIDBAU=\",\"name\":\"example\"}"
True
为了更明确一点,我们对ToJSON
的{{1}}和FromJSON
的定义发生了真正的魔力:
ByteString
简而言之,这为我们希望它如何序列化(严格)instance FromJSON ByteString where
parseJSON (String t) = pure $ (either (const "") id . decode . encodeUtf8) t
parseJSON _ = App.empty
instance ToJSON ByteString where
toJSON = String . decodeUtf8 . encode
类型的任何实例提供了Aeson方向。现在遇到的任何ByteString
实例都将按照我们的指定自动编码和解码(请注意ByteString
看起来像“典型的”Aeson定义。当然,如果您只想编码特定 MyObject
,您可以放弃ByteString
定义,并在instance
序列化代码中执行此操作。
MyObject
只需调用输入中base64库中的ToJSON
,并将生成的encode
(来自ByteString
调用)转换为encode
对象,它是Text
构造函数的输入(必须从此函数返回的一种Aeson String
)。
Value
看起来有点可怕,但 - 原则上 - 非常相似。我们接受FromJSON
类型的Aeson Value
(对于我们返回的任何其他内容String
),我们将empty
对象中包含的Text
值转换为{ {1}}。然后,我们将此String
提供给base64 ByteString
方法,该方法生成ByteString
(取决于它是否可以成功解码decode
)。我们只是在失败的情况下返回一个空字符串,否则我们将解码后的值提供给对象。
主要功能用作简单的健全性检查。我首先编码Either
(包含一个5字节的二进制字符串)并打印其值。在下一行中,我们将该输出称为ByteString
。我们解码exampleObject
并将其与我们在内存中构造的内存进行比较。这些值 - 如预期的那样 - 彼此相等,因此您可以看到编码和解码正常工作。