Menu

URL và query string trong JavaScript: URL và URLSearchParams

Cách phân tích, tạo và chỉnh sửa URL trong JavaScript bằng API URL và URLSearchParams, không cần regex và không dính bug ở các trường hợp đặc biệt.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Đừng phân tích URL bằng các mẹo xử lý chuỗi nữa

Trước khi có API URL, người ta cắt URL bằng split('?'), regex và cầu may. Cách đó phần lớn vẫn chạy, cho đến khi một giá trị chứa &, =, khoảng trắng hoặc ký tự ngoài ASCII, và lúc đó thì hỏng. Cả trình duyệt lẫn Node đều có sẵn một bộ phân tích đúng chuẩn. Hãy dùng nó.

Chỉ một lời gọi, mọi phần của URL đã được tách riêng và giải mã đúng. Hàm khởi tạo ném ra TypeError với đầu vào không hợp lệ, và đó thường là điều bạn muốn: một URL rác nên thất bại rõ ràng, thay vì lặng lẽ tạo ra dữ liệu rác ở phía sau.

Đọc tham số query

Mỗi URL có thuộc tính .searchParams: một đối tượng URLSearchParams biết cách đọc và ghi query string:

Vài điều đáng chú ý:

  • Giá trị trả về đã được giải mã. ?name=Ada%20Lovelace cho bạn "Ada Lovelace".
  • Mọi thứ đều là chuỗi. "2" không phải 2. Hãy chuyển đổi bằng Number() nếu bạn cần số.
  • Khóa lặp lại là hợp lệ. get trả về giá trị khớp đầu tiên; getAll trả về mọi giá trị khớp.
  • Khóa không tồn tại trả về null, không phải undefined, nên ?? "default" dùng rất hợp với chúng.

Tạo query string

Bạn có thể tạo query string từ đầu bằng URLSearchParams, không cần tự thoát ký tự, không cần nối bằng &:

Hoặc tạo từ một đối tượng: bất kỳ iterable nào chứa các cặp [key, value] đều được, và một đối tượng thông thường cũng vậy:

set và append: set thay thế mọi giá trị đang có của khóa đó. append thêm một giá trị nữa. Dùng append khi một khóa có thể lặp lại một cách hợp lệ (tag, bộ lọc); dùng set cho các tham số chỉ có một giá trị.

Chỉnh sửa URL

Vì URL là một đối tượng "sống", việc thay đổi searchParams tự động cập nhật .search và .href:

Đây là cách viết chuẩn để thêm một tham số query vào URL có sẵn. Không cần kiểm tra "URL đã có ? chưa", không phải lo nên thêm & hay ? ở trước.

Bạn có thể thay đổi các phần khác của URL theo cách tương tự:

Duyệt qua các tham số

URLSearchParams là một iterable. for...of cho bạn các cặp [key, value], và có sẵn các hàm hỗ trợ quen thuộc keys(), values() và entries():

Lưu ý rằng các khóa lặp lại sẽ xuất hiện nhiều lần: bạn sẽ thấy tag = web rồi tag = beginner như hai mục riêng biệt. Điều đó phản ánh đúng query string thực tế.

Nếu bạn muốn một đối tượng thông thường để in ra gỡ lỗi nhanh, Object.fromEntries dùng được, nhưng nó gộp các khóa lặp lại và chỉ giữ giá trị cuối cùng:

Dùng để gỡ lỗi thì được. Sai nếu có khóa nào có thể lặp lại.

URL tương đối cần một URL gốc

Riêng new URL("/search?q=js") sẽ ném lỗi: một đường dẫn tương đối tự nó không phải URL hợp lệ. Hãy truyền một URL gốc làm đối số thứ hai:

Quy tắc phân giải giống hệt quy tắc trình duyệt dùng cho <a href>: dấu / ở đầu là tuyệt đối tính từ host, không có dấu gạch chéo là tương đối so với đường dẫn hiện tại, .. đi lên một cấp. Rất tiện khi bạn ghép URL API từ một URL gốc đã cấu hình.

Trên trình duyệt, window.location.href là một URL gốc có sẵn để phân tích URL của trang hiện tại:

const u = new URL(window.location.href);
const page = u.searchParams.get("page") ?? "1";

Xử lý URL không hợp lệ

Hàm khởi tạo URL ném lỗi khi đầu vào sai định dạng. Điều đó hữu ích, nhưng cũng có nghĩa là bạn cần try/catch khi phân tích bất cứ thứ gì người dùng nhập hoặc hệ thống bên ngoài gửi tới:

Các môi trường hiện đại còn cung cấp URL.canParse(input): một phép kiểm tra trả về boolean, giúp tránh rườm rà với try/catch khi bạn chỉ muốn xác thực:

Một ví dụ nhỏ hoàn chỉnh

Ghép tất cả lại: đọc các bộ lọc hiện tại từ một URL, điều chỉnh chúng và tạo ra một URL mới để chuyển tới:

Truyền null sẽ xóa tham số. Mọi giá trị khác sẽ đặt mới hoặc ghi đè nó. Đó là mẫu bạn sẽ viết dưới dạng này hay dạng khác mỗi khi xây dựng giao diện bộ lọc, phân trang hoặc deep link.

Những điều cần nhớ

  • new URL(string) phân tích một URL thành các phần có tên. Nó ném lỗi khi gặp dữ liệu rác.
  • url.searchParams là một URLSearchParams: dùng get, getAll, set, append, delete, has.
  • Việc mã hóa được làm sẵn cho bạn. Đừng dùng encodeURIComponent trừ khi bạn tự tay ghép chuỗi.
  • Truyền một URL gốc làm đối số thứ hai để phân giải đường dẫn tương đối.
  • URL.canParse (hoặc try/catch) là công cụ xác thực cho đầu vào không đáng tin.

Mỗi khi bạn định tách URL bằng .split('?') hay lấy một tham số query bằng regex, hãy dùng những API này thay vào đó. Chúng ngắn hơn, đúng hơn và đã có sẵn trong môi trường chạy.

Câu hỏi thường gặp

Làm sao phân tích một URL trong JavaScript?

Truyền chuỗi vào hàm khởi tạo URL: const u = new URL('https://example.com/path?x=1'). Đối tượng nhận được có các thuộc tính protocol, host, pathname, search, hash và một công cụ hỗ trợ searchParams. Hàm khởi tạo ném lỗi với URL không hợp lệ, nên hãy bọc nó trong try/catch khi phân tích đầu vào không đáng tin.

Làm sao lấy một tham số trong query string bằng JavaScript?

Dùng url.searchParams.get('name'). Nó trả về giá trị đã được giải mã, hoặc null nếu tham số không có. Với những tham số có thể lặp lại (?tag=a&tag=b), hãy dùng searchParams.getAll('tag') để lấy mọi giá trị dưới dạng mảng.

URL và URLSearchParams khác nhau thế nào?

URL phân tích và biểu diễn toàn bộ một URL: protocol, host, đường dẫn, query, hash. URLSearchParams chỉ là phần query string, và bạn có thể dùng riêng nó để tạo hoặc phân tích các chuỗi a=1&b=2. Mỗi instance của URL có thuộc tính .searchParams, là một URLSearchParams gắn với URL đó.

Có cần tự mã hóa tham số query không?

Không. URLSearchParams tự động mã hóa khóa và giá trị khi bạn gọi set, append hoặc đọc lại chuỗi. Nó xử lý đúng khoảng trắng, &, = và Unicode. Chỉ dùng tới encodeURIComponent khi bạn tự tay ghép chuỗi, điều mà thường bạn không nên làm.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu