Bối cảnhBạn đang dán mắt vào terminal lúc 2 giờ sáng, và một dòng chữ duy nhất cứ trêu ngươi bạn: SyntaxError: Unexpected end of JSON input. Lỗi này là một "nghi thức trưởng thành" trong quá trình phát triển Node.js. Nó thường xuất hiện khi bạn đang xử lý các phản hồi API, đọc các tệp cấu hình cục bộ hoặc truyền dữ liệu giữa các dịch vụ.
Nói một cách đơn giản, lỗi này có nghĩa là JSON.parse() đã bắt đầu đọc một chuỗi và mong đợi có thêm dữ liệu để hoàn thành một cấu trúc hợp lệ, nhưng chuỗi đó lại dừng lại một cách bất ngờ. Nó giống như việc một người phục vụ dọn đĩa của bạn đi khi bạn vẫn đang ăn dở. Thông thường, thủ phạm không phải là lỗi đánh máy trong JSON của bạn—mà là do dữ liệu là một chuỗi rỗng, undefined, hoặc một gói tin mạng bị cắt ngắn.
Quy trình gỡ lỗiĐừng tìm kiếm các dấu phẩy bị thiếu nữa. Khi gặp lỗi này, sai lầm đầu tiên mà hầu hết các lập trình viên mắc phải là kiểm tra cấu trúc của JSON. Đừng làm vậy vội. Thay vào đó, hãy xác minh sự tồn tại của dữ liệu.
1. Ghi nhật ký dữ liệu thô (Raw Input)Trước khi bạn gọi JSON.parse() hoặc res.json(), hãy kiểm tra dữ liệu thô. Nếu bạn đang sử dụng Fetch API, đừng nhảy thẳng vào .json(). Hãy sử dụng .text() trước để xem các ký tự thực tế được truyền qua mạng.
// Gỡ lỗi một lời gọi fetch
const response = await fetch('https://api.example.com/data');
const rawText = await response.text();
console.log('Raw output:', rawText);
console.log('Byte length:', rawText.length);
// Chỉ parse nếu chúng ta thực sự có nội dung
const data = rawText ? JSON.parse(rawText) : {};
Nếu rawText là một chuỗi rỗng (""), JSON.parse() sẽ thất bại 100%. Một phản hồi 0-byte là nguyên nhân phổ biến nhất của cơn đau đầu này.
2. Kiểm tra mã trạng thái HTTPMột phản hồi 204 No Content hoặc 404 Not Found thường trả về một thân (body) hoàn toàn trống rỗng. Nếu logic của bạn giả định một phản hồi 200 OK thành công với dữ liệu hợp lệ, mã sẽ bị lỗi ngay khi nó cố gắng parse khoảng trống đó.
Các kịch bản phổ biến và giải pháp### Kịch bản A: Phản hồi API trốngNhiều REST API hiện đại trả về thân trống cho các yêu cầu DELETE hoặc PUT requests. Nếu mã của bạn cố gắng parse kết quả của một thao tác xóa, nó có khả năng sẽ ném ra một lỗi.
const res = await fetch(url, { method: 'DELETE' });
// Dòng này sẽ bị lỗi nếu máy chủ trả về 204 No Content
const body = await res.json();
Cách khắc phục: Kiểm tra mã trạng thái hoặc độ dài nội dung trước khi bạn cố gắng parse.
const res = await fetch(url, { method: 'DELETE' });
let data = {};
if (res.status !== 204 && res.ok) {
data = await res.json();
}
Kịch bản B: Đọc một tệp 0-byteSử dụng fs.readFileSync để tải một tệp cấu hình? Nếu tệp đó trống—có lẽ do một thao tác ghi thất bại trước đó—trình phân tích cú pháp (parser) sẽ bị nghẽn.
const fs = require('fs');
// Nếu config.json là 0 byte, dòng này sẽ ném ra lỗi
const config = JSON.parse(fs.readFileSync('./config.json', 'utf8'));
Cách khắc phục: Xác thực rằng chuỗi có nội dung trước khi chuyển nó cho trình phân tích cú pháp.
const rawConfig = fs.readFileSync('./config.json', 'utf8');
const config = rawConfig.trim() ? JSON.parse(rawConfig) : {};
Kịch bản C: Luồng dữ liệu (Stream) bị cắt ngắnKhi thu thập các đoạn dữ liệu (chunks) từ một Node.js stream, bạn có thể đang parse dữ liệu trước khi sự kiện end được kích hoạt. Ngoài ra, kết nối mạng có thể đã bị ngắt giữa chừng, để lại cho bạn một nửa đối tượng JSON như {"user": "admin", "status": .
let body = '';
req.on('data', chunk => {
body += chunk;
});
req.on('end', () => {
try {
const data = JSON.parse(body);
} catch (e) {
console.error("Nhận được JSON không đầy đủ. Kết nối có khả năng đã bị ngắt.");
}
});
Các bước xác minhHãy giả lập một lỗi để đảm bảo cách khắc phục của bạn thực sự hoạt động. Bạn có thể sử dụng một công cụ như Postman để giả lập phản hồi 200 OK với thân 0-byte. Nếu ứng dụng của bạn vượt qua điều này mà không bị sập, bạn đang đi đúng hướng.
Viết một unit test truyền một chuỗi rỗng và một chuỗi JSON không đầy đủ (như {"id": 1) vào hàm parsing của bạn. Nó nên trả về một giá trị mặc định hoặc một lỗi tùy chỉnh hữu ích thay vì để lỗi SyntaxError chung chung nổi lên.
Phòng ngừa và các thực hành tốt nhấtLuôn bao bọc JSON.parse() trong một khối try-catch. JSON là dữ liệu bên ngoài, và bạn không bao giờ nên tin tưởng nó. Không quan trọng nếu tài liệu API hứa hẹn một đối tượng hoàn hảo; mạng lưới luôn không đáng tin cậy.
Nếu bạn đang xử lý các payload khổng lồ liên tục thất bại, hãy thử sao chép đầu ra thô vào một công cụ xác thực. Tôi sử dụng JSON Formatter & Validator trên ToolCraft. Nó rất hữu ích để phát hiện các ký tự không in được bị ẩn hoặc xem chính xác nơi payload bị cắt đứt. Vì nó chạy trong trình duyệt, bạn không rủi ro việc gửi các nhật ký production nhạy cảm đến một máy chủ ngẫu nhiên nào đó.

