Tuần tự hóa là quá trình chuyển đổi một đối tượng hoặc cấu trúc dữ liệu thành định dạng tuần tự phù hợp để truyền qua mạng hoặc lưu trữ trong tập tin. Quá trình ngược lại, giải tuần tự hóa, khôi phục dữ liệu về trạng thái ban đầu. Theo MDN Web Docs, tuần tự hóa là cần thiết cho mọi giao tiếp giữa các tiến trình. Tuần tự hóa là nền tảng của API REST, bộ nhớ đệm và trao đổi dữ liệu giữa các thành phần ứng dụng.
Điểm chính
Tuần tự hóa là quá trình chuyển đổi một đối tượng trong RAM thành một chuỗi byte hoặc ký tự tuyến tính có thể được truyền qua mạng, lưu vào tập tin hoặc chuyển cho một tiến trình khác. Nếu không có tuần tự hóa, giao tiếp mạng, duy trì trạng thái và tương tác giữa các tiến trình sẽ không thể thực hiện được.
Tuần tự hóa bao gồm hai quá trình đối lập. Quá trình thuận (tuần tự hóa) đóng gói dữ liệu vào định dạng truyền. Quá trình ngược (giải tuần tự hóa) khôi phục dữ liệu trở lại đối tượng. Giải tuần tự hóa rất quan trọng đối với bảo mật: dữ liệu đầu vào không chính xác có thể dẫn đến lỗ hổng bảo mật trong ứng dụng.
Trong phát triển ứng dụng di động, tuần tự hóa được sử dụng ở khắp mọi nơi: gửi yêu cầu đến máy chủ và xử lý phản hồi, lưu trạng thái ứng dụng khi xoay màn hình, lưu dữ liệu vào bộ nhớ đệm trên đĩa và truyền dữ liệu giữa các màn hình qua Intent (Android) hoặc Segue (iOS).
Định dạng tuần tự hóa được chia thành dạng văn bản và nhị phân. Định dạng văn bản (JSON, XML) có thể đọc được bởi con người và không cần công cụ để xem. Định dạng nhị phân (Protobuf, FlatBuffers, MessagePack) nhỏ gọn hơn và nhanh hơn nhưng không thể đọc được nếu không giải tuần tự hóa. Việc chọn định dạng là sự đánh đổi giữa hiệu suất và sự thuận tiện khi gỡ lỗi.
Ngoài JSON, XML và Protobuf, còn có các định dạng chuyên dụng: FlatBuffers của Google cho trò chơi và AR, MessagePack — thay thế nhị phân nhỏ gọn cho JSON, Avro của Apache cho dữ liệu lớn trong Kafka, YAML — định dạng cấu hình hỗ trợ chú thích.
| Định dạng | Loại | Lược đồ | Kích thước | Tốc độ |
|---|---|---|---|---|
| JSON | Văn bản | Tùy chọn | Trung bình | Trung bình |
| XML | Văn bản | XSD | Lớn | Thấp |
| Protobuf | Nhị phân | Bắt buộc | Nhỏ | Cao |
| FlatBuffers | Nhị phân | Bắt buộc | Nhỏ | Tối đa |
| MessagePack | Nhị phân | Không | Nhỏ | Cao |
| Avro | Nhị phân | JSON Schema | Nhỏ | Cao |
Tuần tự hóa trên nền tảng di động có những đặc thù riêng: băng thông hạn chế, bộ xử lý yếu hơn và nhu cầu duy trì trạng thái khi xoay màn hình. Trên Android sử dụng Gson, Moshi, Kotlinx Serialization. Trên iOS — Codable, JSONSerialization, PropertyListEncoder. Việc chọn đúng thư viện ảnh hưởng nghiêm trọng đến hiệu suất ứng dụng.
Kotlinx Serialization là thư viện hiện đại của JetBrains dành cho Kotlin Multiplatform Mobile. Nó hỗ trợ JSON, Protobuf, CBOR và các định dạng tùy chỉnh. Việc tạo mã diễn ra ở thời điểm biên dịch thông qua plugin Kotlin Serialization, đảm bảo hiệu suất cao mà không sử dụng phản xạ.
Thư viện Kotlinx Serialization sử dụng chú thích @Serializable cho các lớp và plugin trình biên dịch để tạo bộ tuần tự hóa. Điều này đảm bảo hiệu suất cao và an toàn kiểu. Định dạng mặc định là JSON, nhưng các định dạng khác được hỗ trợ thông qua các mô-đun bổ sung.
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString
@Serializable
data class Project(
val id: Int,
val name: String,
val platforms: List<String>,
val active: Boolean
)
val json = Json {
prettyPrint = true
ignoreUnknownKeys = true
encodeDefaults = true
}
fun main() {
val project = Project(1, "MobileApp",
listOf("Android", "iOS"), true)
// Tuần tự hóa
val jsonString = json.encodeToString(project)
// Giải tuần tự hóa
val restored = json.decodeFromString<Project>(jsonString)
}
Giao thức Codable là cơ chế tuần tự hóa tích hợp sẵn trong Swift. Nó kết hợp các giao thức Encodable (tuần tự hóa) và Decodable (giải tuần tự hóa). JSONEncoder và JSONDecoder tự động xử lý các cấu trúc lồng nhau, mảng, giá trị tùy chọn và khóa tùy chỉnh thông qua CodingKeys.
import Foundation
struct AppConfig: Codable {
let appName: String
let version: String
let features: [String]
let isProduction: Bool
}
let config = AppConfig(
appName: "MyApp",
version: "2.1.0",
features: ["push", "analytics", "offline"],
isProduction: true
)
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
guard let data = try? encoder.encode(config) else { return }
let jsonString = String(data: data, encoding: .utf8)
Hiệu suất của các định dạng tuần tự hóa được đánh giá qua ba chỉ số: kích thước thông điệp, tốc độ tuần tự hóa và tốc độ giải tuần tự hóa. Đối với ứng dụng di động, cả ba chỉ số đều quan trọng: kích thước ảnh hưởng đến lưu lượng và thời gian tải, tốc độ ảnh hưởng đến khả năng phản hồi của giao diện và thời gian khởi động ứng dụng.
Protobuf và FlatBuffers cho thấy kết quả tốt nhất nhờ biểu diễn nhị phân. FlatBuffers nổi bật vì không yêu cầu bước giải tuần tự hóa riêng — dữ liệu được đọc trực tiếp từ bộ đệm nhị phân, lý tưởng cho trò chơi và ứng dụng AR với yêu cầu độ trễ tối thiểu. JSON vẫn là định dạng phổ biến nhất cho API REST, mặc dù hiệu suất kém hơn, nhờ vào tính đơn giản và phổ quát của nó.
| Kịch bản | Định dạng được khuyên dùng | Lý do |
|---|---|---|
| API REST | JSON | Tính phổ quát, dễ đọc, hỗ trợ |
| Microservices | Protobuf | Tính gọn nhẹ, tốc độ, gRPC |
| Trò chơi / AR | FlatBuffers | Zero-copy, độ trễ tối thiểu |
| Dữ liệu lớn | Avro | Tương thích với Kafka và Hadoop |
| Cấu hình | YAML | Chú thích, dễ đọc |
| Bố cục Android | XML | Tiêu chuẩn nền tảng |
Các thử nghiệm thực tế trên tập dữ liệu gồm 1000 đối tượng người dùng cho thấy: Protobuf tạo thông điệp 12 KB (JSON — 85 KB, XML — 120 KB). Thời gian tuần tự hóa: Protobuf — 2 ms, JSON — 8 ms, XML — 25 ms. Những con số này làm cho định dạng nhị phân trở nên ưu tiên cho các hệ thống tải cao và ứng dụng di động có lưu lượng hạn chế.
Các ví dụ thể hiện việc tuần tự hóa cùng một đối tượng trong các định dạng khác nhau. Điều này giúp so sánh trực quan về kích thước và khả năng đọc. Cùng một đối tượng User sẽ được tuần tự hóa thành JSON, XML và Protobuf — có thể thấy rõ JSON nhỏ gọn hơn XML, và Protobuf là nhỏ gọn nhất nhưng không thể đọc được.
JSON — cú pháp tối giản, khóa trong dấu ngoặc kép, giá trị nhiều loại. Chiếm 80 ký tự. Khả năng đọc cao, cấu trúc trực quan rõ ràng. Phù hợp cho API nơi tốc độ phát triển và gỡ lỗi quan trọng.
XML — mỗi phần tử được bọc trong thẻ mở và thẻ đóng. Chiếm 150 ký tự. Khả năng đọc trung bình, cấu trúc nghiêm ngặt. Phù hợp cho luồng tài liệu và các hệ thống yêu cầu xác thực XSD.
Protobuf — nhị phân, 32 byte cho dữ liệu này. Không thể đọc — cần giải tuần tự hóa để xem. Kích thước tối thiểu làm cho nó lý tưởng cho các hệ thống tải cao và ứng dụng di động.
{
"id": 42,
"name": "IT Sectr",
"email": "team@itsectr.com",
"role": "admin",
"active": true
}
<user>
<id>42</id>
<name>IT Sectr</name>
<email>team@itsectr.com</email>
<role>admin</role>
<active>true</active>
</user>
Các thực hành tốt nhất giúp tránh các lỗi thường gặp và chọn chiến lược tuần tự hóa phù hợp cho dự án. Tuân theo các khuyên nghị này cải thiện hiệu suất, bảo mật và khả năng bảo trì mã.
Bảo mật tuần tự hóa là một khía cạnh cực kỳ quan trọng, đặc biệt khi giải tuần tự hóa dữ liệu từ các nguồn không đáng tin cậy. Các cuộc tấn công giải tuần tự hóa có thể dẫn đến thực thi mã từ xa (RCE), một trong những lỗ hổng nguy hiểm nhất trong ứng dụng web và di động. Các trường hợp nổi tiếng nhất liên quan đến Java Serializable và Python pickle.
Protobuf và JSON có bảo vệ tích hợp sẵn chống lại các cuộc tấn công như vậy vì chúng chỉ làm việc với dữ liệu, không phải với các đối tượng tùy ý. Ngược lại, Java Serializable có thể khôi phục bất kỳ lớp nào có trong classpath, khiến nó trở nên nguy hiểm khi nhận dữ liệu từ nguồn bên ngoài. Trên Android, nên sử dụng Kotlinx Serialization hoặc Moshi thay vì Java Serialization tiêu chuẩn.
Các biện pháp bảo mật bổ sung: đặt giới hạn kích thước dữ liệu đầu vào, xác thực lược đồ trước khi giải tuần tự hóa, không tin vào Content-Type từ tiêu đề HTTP, sử dụng danh sách cho phép (allowlist) cho các lớp được phép. Thường xuyên cập nhật các thư viện tuần tự hóa vì các lỗ hổng định kỳ được phát hiện và sửa chữa.
Câu hỏi thường gặp
Tuần tự hóa chuyển đối tượng thành chuỗi byte, trong khi marshalling truyền dữ liệu giữa các không gian địa chỉ khác nhau trong khi vẫn giữ nguyên kiểu và cấu trúc. Marshalling bao gồm tuần tự hóa như một phần của quá trình, nhưng cũng có thể bao gồm mã hóa tham chiếu và quản lý bộ nhớ.
FlatBuffers của Google cung cấp tốc độ tối đa nhờ giải tuần tự hóa zero-copy — dữ liệu được đọc trực tiếp từ bộ đệm nhị phân mà không cần chuyển đổi. Protobuf đứng thứ hai, JSON thứ ba. XML là định dạng chậm nhất trong số các định dạng phổ biến.
Kotlinx Serialization là lựa chọn tốt nhất cho các dự án Kotlin mới: tạo mã khi biên dịch, hỗ trợ Kotlin Multiplatform, null safety. Moshi là lựa chọn tốt cho các dự án Java, hiệu suất cao hơn Gson. Gson là thư viện đơn giản nhất để bắt đầu nhưng chậm hơn và sử dụng phản xạ.
Các tham chiếu vòng dẫn đến đệ quy vô hạn trong quá trình tuần tự hóa. Giải pháp: sử dụng tham chiếu ID thay vì tham chiếu trực tiếp đến đối tượng, áp dụng các bộ chuyển đổi tuần tự hóa chuyên dụng (ví dụ: @JsonIgnore trong Jackson), hoặc thiết kế lại mô hình dữ liệu để loại bỏ các vòng lặp.
Có, đặc biệt là giải tuần tự hóa dữ liệu không đáng tin cậy. Lỗ hổng giải tuần tự hóa có thể dẫn đến thực thi mã từ xa. Khuyên nghị: không giải tuần tự hóa dữ liệu từ các nguồn không đáng tin cậy, sử dụng danh sách cho phép các lớp khi giải tuần tự hóa và xác thực lược đồ dữ liệu trước khi xử lý.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm