Ô tìm kiếm nhận cà phê & trà+đá. Nếu nối thẳng chuỗi này sau ?q=, dấu & có thể trở thành ranh giới giữa hai tham số. Lỗi thường lộ ra với dữ liệu thật, dù từ khóa hello chạy bình thường.
URLSearchParams và encodeURIComponent() đều có thể tham gia giải quyết việc mã hóa dữ liệu trong query. Chúng có phạm vi khác nhau: một bên quản lý tập cặp khóa–giá trị, bên còn lại mã hóa một thành phần chuỗi. Bài so sánh theo cùng tiêu chí và dùng ví dụ tự tạo, đối chiếu MDN ngày 27/10/2026; không có đo thời gian hay bộ nhớ.
1. Cách bắt đầu và mức kiểm soát
Ví dụ dưới chạy bằng Node.js 24.18.1, không cài dependency và không gửi request mạng. example.com chỉ là địa chỉ minh họa.
const term = 'cà phê & trà+đá';
const manual = new URL(
'https://example.com/search?q=' + encodeURIComponent(term)
);
const managed = new URL('https://example.com/search');
managed.searchParams.set('q', term);
console.log(manual.searchParams.get('q') === term);
console.log(managed.searchParams.get('q') === term);
console.log(manual.search);
console.log(managed.search);
Hai dòng boolean đều là true. Query của cách thứ nhất dùng %20 cho khoảng trắng; cách thứ hai dùng +. Dấu cộng thuộc dữ liệu được mã hóa thành %2B, nên vẫn đọc lại đúng. Hai chuỗi query có thể khác byte mà cùng khôi phục một giá trị theo cách parse này.
Với đúng một tham số, mã hóa giá trị rồi nối chuỗi vẫn dễ kiểm tra. Khi số tham số tăng, người viết phải tự quản lý dấu ?, dấu &, khóa và tình huống tham số đã tồn tại. URL.searchParams đặt phần việc đó vào API có cấu trúc.
2. Tham số lặp và thay đổi giá trị
const filter = new URL('https://example.com/search?page=1');
filter.searchParams.append('tag', 'flutter');
filter.searchParams.append('tag', 'react native');
console.log(filter.searchParams.getAll('tag'));
filter.searchParams.set('page', '2');
console.log(filter.searchParams.get('page'));
console.log(filter.searchParams.getAll('tag').length);
Kết quả là hai tag theo thứ tự thêm, page bằng '2' và số tag bằng 2. append diễn đạt việc thêm một giá trị; set diễn đạt thay thế giá trị của khóa. Dùng getAll khi server chấp nhận nhiều giá trị cho cùng khóa, thay vì chỉ nhìn get rồi kết luận tag bị mất.
encodeURIComponent không quản lý khái niệm khóa lặp. Bạn vẫn có thể tự dựng đúng, nhưng phải giữ logic danh sách, phân tách và cập nhật ở code gọi. Đây là chi phí bảo trì, không phải hạn chế về khả năng biểu diễn dữ liệu.
3. So sánh để chọn trong dự án
| Tiêu chí | URLSearchParams | encodeURIComponent và ghép chuỗi |
|---|---|---|
| Bắt đầu với một giá trị | Có thêm đối tượng query hoặc URL | Ngắn nếu template cố định |
| Kiểm soát khóa lặp | Có append, set, getAll | Tự quản lý cấu trúc |
| Tích hợp URL có sẵn | URL.searchParams cập nhật query | Cần tự giữ các phần URL |
| Hệ sinh thái | API Web có sẵn ở runtime hiện đại | Hàm JavaScript tích hợp |
| Hiệu năng | Bài chưa đo | Bài chưa đo |
| Chi phí vận hành | Không cần dịch vụ ngoài trong ví dụ | Không cần dịch vụ ngoài trong ví dụ |
Với bộ lọc tìm kiếm có nhiều lựa chọn, tôi chọn URL cùng searchParams vì thao tác thêm, xóa và thay thế dễ đọc. Nếu một thư viện yêu cầu bạn cung cấp riêng một thành phần đã mã hóa, encodeURIComponent có thể đúng tầng trách nhiệm hơn. Hãy đọc hợp đồng của thư viện trước khi truyền vào.
4. Ba lỗi cần đưa vào kiểm tra
Đầu tiên là mã hóa hai lần. Truyền encodeURIComponent(term) vào searchParams.set khiến dấu % của chuỗi trung gian lại bị mã hóa. Giá trị đọc lại là chuỗi đã encode, không còn bằng term. Với API khóa–giá trị, hãy truyền giá trị gốc.
Thứ hai, new URLSearchParams(fullUrl) không phải cách parse một URL đầy đủ. Hãy dùng new URL(fullUrl).searchParams. Thứ ba, nếu truyền query dạng chuỗi chứa dấu cộng chưa encode, parser có thể hiểu nó thành khoảng trắng. Dùng append hoặc set cho dữ liệu gốc thay vì nội suy dữ liệu vào cú pháp query.
Thêm fixture cho chuỗi rỗng, dấu &, dấu cộng, #, tiếng Việt và khóa lặp. Với một API đặc biệt hoặc URL có chữ ký, kiểm tra quy tắc chuẩn hóa của bên nhận; không tự thay %20 bằng + rồi giả định chữ ký vẫn hợp lệ.
Phạm vi bằng chứng
Các snippet và các trường hợp encode hai lần đã được chạy trên Node.js trong lượt biên tập. Chúng kiểm tra việc dựng và đọc lại URL cục bộ, chưa kiểm tra server đích hay engine JavaScript trên thiết bị mobile. Mã hóa query cũng không thay thế kiểm tra quyền truy cập hoặc validation nghiệp vụ ở backend.
Chọn theo lớp dữ liệu bạn đang thao tác và giữ các ca ký tự đặc biệt trong kiểm tra. Không cần một thư viện mạng để chứng minh query còn giữ đúng từ khóa của người dùng.


