序列化(Serialization)是程式設計中將物件、資料結構或狀態轉換為可儲存或傳輸的位元組流(byte stream)的過程,反向操作稱為反序列化(Deserialization)。它解決了物件在記憶體中無法直接跨進程、跨網路或持久化儲存的問題,讓複雜資料結構能在檔案、資料庫、快取或 API 中無縫傳遞,是現代應用不可或缺的基礎技術。
序列化的核心目的與原理
序列化將記憶體中動態物件轉為靜態位元組序列,保留完整結構資訊:
物件狀態 → 序列化 → 位元組流 → 儲存/傳輸 → 反序列化 → 物件狀態
User(id=1, name="Alice") → b'x00x01Alice' → 檔案/網路 → User(id=1, name="Alice")
關鍵挑戰:
-
保留類型資訊(String vs int)
-
處理巢狀物件(物件內含物件)
-
跨語言/平台相容性
-
版本相容性(類別結構變更)
常見序列化格式比較
| 格式 | 可讀性 | 效能 | 跨語言 | 用途 | 範例 |
|---|---|---|---|---|---|
| JSON | 高 | 中 | 優秀 | API、設定檔 | {"name": "Alice", "age": 25} |
| XML | 高 | 慢 | 好 | 企業整合、SOAP | <user><name>Alice</name></user> |
| Protocol Buffers | 低 | 快 | 優秀 | gRPC、高效能 RPC | 08 01 12 05 41 6c 69 63 65 |
| MessagePack | 中 | 快 | 優秀 | 即時通訊 | 二進位 JSON |
| BSON | 低 | 中 | 中 | MongoDB | JSON 二進位擴展 |
程式語言實作範例
Python(JSON + pickle)
import json
import pickle
from dataclasses import asdict
@dataclass
class User:
id: int
name: str
email: str
user = User(1, "Alice", "[email protected]")
# JSON 序列化(需可轉 JSON)
user_dict = asdict(user)
json_str = json.dumps(user_dict)
print(json_str) # {"id": 1, "name": "Alice", "email": "[email protected]"}
# Python 原生(pickle,二進位)
serialized = pickle.dumps(user)
deserialized = pickle.loads(serialized)
print(deserialized) # User(id=1, name='Alice', email='[email protected]')
JavaScript(JSON 原生支援)
const user = { id: 1, name: 'Alice', email: '[email protected]' };
// 序列化
const jsonString = JSON.stringify(user);
console.log(jsonString); // {"id":1,"name":"Alice","email":"[email protected]"}
// 反序列化
const userObj = JSON.parse(jsonString);
console.log(userObj.id); // 1
Java(Jackson + Gson)
import com.fasterxml.jackson.databind.ObjectMapper;
User user = new User(1, "Alice", "[email protected]");
ObjectMapper mapper = new ObjectMapper();
// 序列化
String json = mapper.writeValueAsString(user);
// 反序列化
User deserialized = mapper.readValue(json, User.class);
序列化在實際場景的應用
1. Web API 資料交換
// Client → Server
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice', email: '[email protected]' })
});
// Server → Client
res.json({ id: 1, name: 'Alice', ... });
2. 快取系統(Redis)
import redis
import json
r = redis.Redis()
user = User(1, "Alice", "[email protected]")
# 序列化儲存
r.setex("user:1", 3600, json.dumps(asdict(user)))
# 反序列化讀取
user_data = json.loads(r.get("user:1"))
3. 訊息佇列(RabbitMQ/Kafka)
# 生產者:序列化發送事件
order_event = {"order_id": 123, "status": "created"}
channel.basic_publish(
exchange='',
routing_key='orders',
body=json.dumps(order_event)
)
# 消費者:反序列化處理
import json
method_frame, header_frame, body = delivery
order = json.loads(body)
4. Session 儲存
// Express + Redis Session
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'keyboard cat',
resave: false,
saveUninitialized: false
}));
進階序列化協議
Protocol Buffers(protobuf)
// user.proto
syntax = "proto3";
message User {
int32 id = 1;
string name = 2;
string email = 3;
}
# 比 JSON 小 3-10 倍,解析快 5-20 倍
user_proto = User(id=1, name="Alice", email="[email protected]")
serialized = user_proto.SerializeToString()
Apache Avro
-
Schema 內嵌,支援 Schema 演化
-
動態類型,跨語言
-
Hadoop 生態標準
序列化安全挑戰
反序列化漏洞(常見資安問題):
// Java 反序列化 RCE 漏洞
ObjectInputStream ois = new ObjectInputStream(input);
Object obj = ois.readObject(); // 危險!可遠端執行程式碼
解決方案:
-
使用 JSON/XML(安全)
-
白名單序列化類別
-
限制反序列化深度
-
改用安全協議(protobuf)
效能與大小比較
原始物件:User {id:1, name:"Alice", email:"[email protected]"}
JSON: 52 bytes
XML: 98 bytes
protobuf:16 bytes (67% 壓縮)
MessagePack:38 bytes
實際效能(1M 物件):
JSON 序列化:1.2s / 反序列化:1.1s
protobuf:0.2s / 0.18s (5-6x 加速)
最佳實務與注意事項
選擇原則:
API 外部:JSON(通用、人可讀)
內部 RPC:protobuf/gRPC(效能)
快取:MessagePack(壓縮)
資料庫:原生格式或 BSON
程式碼實務:
# 版本控制
class UserV1:
id: int
name: str
class UserV2(UserV1):
id: int
name: str
email: str # 向後相容
# 驗證序列化資料
def safe_deserialize(data):
try:
obj = json.loads(data)
UserSchema().load(obj) # pydantic 驗證
return obj
except ValidationError:
raise ValueError("無效資料格式")
常見錯誤:
# 忘記處理 None/null
json.dumps({'user': None}) # 跨語言問題
# 循環引用
class Node:
def __init__(self, value, next=None):
self.value = value
self.next = next # 序列化無限循環
序列化是分散式系統的血液,從 REST API 到微服務通訊,從快取到訊息佇列,無處不在。選擇適合格式(JSON 通用、protobuf 效能)、注意安全(避免反序列化漏洞)、支援版本演化,就能打造可靠的資料交換管道,提升系統效能與穩定性。