URLPattern đưa việc định tuyến đến nền tảng web

Phương pháp chuẩn hoá các trường hợp sử dụng so khớp mẫu phổ biến.

Thông tin khái quát

Định tuyến là một phần quan trọng của mọi ứng dụng web. Về cơ bản, việc định tuyến bao gồm việc lấy một URL, áp dụng một số phương thức so khớp mẫu hoặc logic khác dành riêng cho ứng dụng cho URL đó, sau đó thường là hiển thị nội dung web dựa trên kết quả. Việc định tuyến có thể được triển khai theo nhiều cách: đôi khi, mã chạy trên máy chủ ánh xạ đường dẫn đến các tệp trên ổ đĩa, hoặc logic trong một ứng dụng trang đơn chờ các thay đổi đối với vị trí hiện tại và tạo một phần DOM tương ứng để hiển thị.

Mặc dù không có tiêu chuẩn rõ ràng nào, nhưng các nhà phát triển web vẫn thường sử dụng cú pháp phổ biến để thể hiện các mẫu định tuyến URL có nhiều điểm chung với regular expressions, nhưng với một số thành phần bổ sung dành riêng cho miền như mã thông báo cho các phân đoạn đường dẫn trùng khớp. Các khung phía máy chủ phổ biến như ExpressRuby on Rails sử dụng cú pháp này (hoặc một cú pháp rất gần với nó) và nhà phát triển JavaScript có thể sử dụng các mô-đun như path-to-regexp hoặc regexpparam để thêm logic đó vào mã của riêng họ.

URLPattern là một tính năng bổ sung cho nền tảng web được xây dựng trên nền tảng do các khung này tạo ra. Mục tiêu của lớp này là chuẩn hoá cú pháp mẫu định tuyến, bao gồm cả khả năng hỗ trợ ký tự đại diện, nhóm mã thông báo có tên, nhóm biểu thức chính quy và đối tượng sửa đổi nhóm. Các thực thể URLPattern được tạo bằng cú pháp này có thể thực hiện các tác vụ định tuyến phổ biến, chẳng hạn như so khớp với các URL đầy đủ hoặc URL pathname và trả về thông tin về mã thông báo và nhóm trùng khớp.

Một lợi ích khác của việc cung cấp tính năng so khớp URL trực tiếp trên nền tảng web là cú pháp phổ biến sau đó có thể được chia sẻ với các API khác cũng cần phải khớp với URL.

Hỗ trợ trình duyệt và đoạn mã polyfill

URLPattern được bật theo mặc định trong Chrome và Edge phiên bản 95 trở lên.

Thư viện urlpattern-polyfill cung cấp một cách sử dụng giao diện URLPattern trong các trình duyệt hoặc môi trường như Nút không được hỗ trợ tích hợp. Nếu bạn sử dụng polyfill, hãy nhớ sử dụng chức năng phát hiện tính năng để đảm bảo rằng bạn chỉ tải polyfill nếu môi trường hiện tại không được hỗ trợ. Nếu không, bạn sẽ mất một trong những lợi ích chính của URLPattern: thực tế là các môi trường hỗ trợ không phải tải xuống và phân tích cú pháp mã bổ sung để sử dụng.

if (!(globalThis && 'URLPattern' in globalThis)) {
  // URLPattern is not available, so the polyfill is needed.
}

Khả năng tương thích về cú pháp

Một triết lý định hướng của URLPattern là tránh việc phát minh lại. Nếu đã quen dùng cú pháp định tuyến trong Express hoặc Ruby on Rails, thì bạn không cần phải tìm hiểu thêm gì mới. Tuy nhiên, do có sự khác biệt nhỏ giữa các cú pháp trong các thư viện định tuyến phổ biến, người dùng phải chọn một cú pháp nào đó làm cú pháp cơ sở và các nhà thiết kế của URLPattern đã quyết định dùng cú pháp mẫu từ path-to-regexp (mặc dù không phải giao diện API) làm điểm xuất phát.

Quyết định này được đưa ra sau khi tham khảo ý kiến chặt chẽ với đơn vị bảo trì hiện tại của path-to-regexp.

Cách tốt nhất để làm quen với phần cốt lõi của cú pháp được hỗ trợ là tham khảo tài liệu về path-to-regexp. Bạn có thể đọc tài liệu dự định phát hành trên MDN trong trang chủ hiện tại trên GitHub.

Các tính năng khác

Cú pháp của URLPattern là tập mẹ của những nội dung path-to-regexp hỗ trợ, vì URLPattern hỗ trợ một tính năng không phổ biến trong số các thư viện định tuyến: so khớp nguồn gốc, bao gồm cả ký tự đại diện trong tên máy chủ. Hầu hết các thư viện định tuyến khác chỉ xử lý tên đường dẫn và đôi khi là phần tìm kiếm hoặc băm của URL. Các công cụ này không bao giờ phải kiểm tra phần gốc của URL, vì chúng chỉ được dùng để định tuyến cùng nguồn gốc trong một ứng dụng web độc lập.

Việc cân nhắc nguồn gốc sẽ tạo ra cơ hội cho các trường hợp sử dụng khác, chẳng hạn như định tuyến các yêu cầu trên nhiều nguồn gốc bên trong trình xử lý sự kiện fetch của trình chạy dịch vụ. Nếu chỉ định tuyến các URL có cùng nguồn gốc, bạn có thể bỏ qua hiệu quả tính năng bổ sung này và sử dụng URLPattern như các thư viện khác.

Ví dụ

Xây dựng mẫu

Để tạo URLPattern, hãy truyền hàm khởi tạo của hàm khởi tạo chuỗi hoặc đối tượng có thuộc tính chứa thông tin về mẫu cần so khớp.

Việc chuyển một đối tượng mang lại khả năng kiểm soát rõ ràng nhất về mẫu cần sử dụng để so khớp từng thành phần URL. Chi tiết nhất có thể là

const p = new URLPattern({
  protocol: 'https',
  username: '',
  password: '',
  hostname: 'example.com',
  port: '',
  pathname: '/foo/:image.jpg',
  search: '*',
  hash: '*',
});

Việc cung cấp một chuỗi trống cho một thuộc tính sẽ chỉ khớp nếu bạn chưa thiết lập phần tương ứng của URL. Ký tự đại diện * sẽ khớp với mọi giá trị của một phần URL nhất định.

Hàm khởi tạo cung cấp một số lối tắt để sử dụng đơn giản hơn. Việc bỏ qua hoàn toàn searchhash hoặc bất kỳ thuộc tính nào khác cũng tương đương với việc đặt các thuộc tính này thành ký tự đại diện '*'. Ví dụ trên có thể được đơn giản hoá thành

const p = new URLPattern({
  protocol: 'https',
  username: '',
  password: '',
  hostname: 'example.com',
  port: '',
  pathname: '/foo/:image.jpg',
});

Có một lối tắt bổ sung, tất cả thông tin về nguồn gốc có thể được cung cấp trong một thuộc tính duy nhất là baseURL, dẫn đến

const p = new URLPattern({
  pathname: '/foo/:image.jpg',
  baseURL: 'https://example.com',
});

Tất cả ví dụ này đều giả định rằng trường hợp sử dụng của bạn có liên quan đến việc so khớp các nguồn gốc. Nếu bạn chỉ muốn so khớp trên các phần khác của URL, ngoại trừ nguồn gốc (như trường hợp định tuyến một nguồn gốc "truyền thống"), thì bạn có thể bỏ qua hoàn toàn thông tin nguồn và chỉ cung cấp một số tổ hợp thuộc tính pathname, searchhash. Như trước đây, các thuộc tính đã bỏ qua sẽ được coi như được đặt thành mẫu ký tự đại diện *.

const p = new URLPattern({pathname: '/foo/:image.jpg'});

Thay vì truyền một đối tượng đến hàm khởi tạo, bạn có thể cung cấp một hoặc hai chuỗi. Nếu bạn cung cấp một chuỗi, chuỗi đó phải đại diện cho một mẫu URL đầy đủ, bao gồm cả thông tin mẫu dùng để khớp với nguồn gốc. Nếu bạn cung cấp 2 chuỗi, thì chuỗi thứ hai sẽ được dùng làm baseURL và chuỗi đầu tiên sẽ được xem là tương ứng với cơ sở đó.

Cho dù bạn cung cấp một hay hai chuỗi, hàm khởi tạo URLPattern sẽ phân tích cú pháp mẫu URL đầy đủ, chia mẫu URL đó thành các thành phần URL và ánh xạ từng phần của mẫu lớn hơn với thành phần tương ứng. Điều này có nghĩa là trong trường hợp này, mỗi URLPattern được tạo bằng các chuỗi sẽ được biểu thị giống như một URLPattern tương đương được tạo bằng một đối tượng. Hàm khởi tạo chuỗi chỉ là một lối tắt, dành cho những người thích giao diện ít chi tiết hơn.

const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');

Khi sử dụng chuỗi để tạo URLPattern, bạn cần lưu ý một số điều sau.

Việc xoá một thuộc tính khi dùng một đối tượng để tạo URLPattern tương đương với việc cung cấp ký tự đại diện * cho thuộc tính đó. Khi mẫu chuỗi URL đầy đủ được phân tích cú pháp, nếu một trong các thành phần URL thiếu giá trị, thì hệ thống sẽ coi thuộc tính của thành phần là '' và sẽ chỉ khớp khi thành phần đó trống.

Khi sử dụng chuỗi, bạn cần đưa ký tự đại diện vào một cách rõ ràng nếu muốn dùng các ký tự đó trong URLPattern đã tạo.

// p1 and p2 are equivalent.
const p1 = new URLPattern('/foo', location.origin);
const p2 = new URLPattern({
  protocol: location.protocol,
  hostname: location.hostname,
  pathname: '/foo',
  search: '',
  hash: '',
});

// p3 and p4 are equivalent.
const p3 = new URLPattern('/foo?*#*', location.origin);
const p4 = new URLPattern({
  protocol: location.protocol,
  hostname: location.hostname,
  pathname: '/foo',
});

Bạn cũng nên lưu ý rằng việc phân tích cú pháp một mẫu chuỗi thành các thành phần có thể không rõ ràng. Có các ký tự như : được tìm thấy trong URL nhưng cũng có ý nghĩa đặc biệt trong cú pháp so khớp mẫu. Để tránh sự không rõ ràng này, hàm khởi tạo URLPattern giả định rằng mọi ký tự đặc biệt đó đều là một phần của một mẫu chứ không phải của URL. Nếu bạn muốn một ký tự không rõ ràng được hiểu là một phần của URL, hãy thoát ký tự đó bằng \` character. For example, the literal URLabout:blankshould be escaped as'about\:blank'` khi được cung cấp dưới dạng chuỗi.

Sử dụng mẫu

Sau khi tạo URLPattern, bạn có 2 cách để sử dụng đối tượng này. Phương thức test()exec() đều lấy cùng một dữ liệu đầu vào và sử dụng cùng một thuật toán để kiểm tra kết quả trùng khớp, và chỉ khác về giá trị trả về. test() trả về true khi có kết quả trùng khớp với dữ liệu đầu vào đã cho và trả về false nếu không. exec() trả về thông tin chi tiết về việc trùng khớp cùng với nhóm thu thập hoặc null nếu không có kết quả trùng khớp. Các ví dụ sau minh hoạ việc sử dụng exec(), nhưng bạn có thể hoán đổi test() cho bất kỳ ví dụ nào trong số đó nếu chỉ muốn một giá trị boolean đơn giản.

Một cách để sử dụng phương thức test()exec() là truyền vào các chuỗi. Tương tự như những gì hàm khởi tạo hỗ trợ, nếu một chuỗi được cung cấp, thì đó phải là một URL đầy đủ, bao gồm cả nguồn gốc. Nếu bạn cung cấp 2 chuỗi, thì chuỗi thứ hai sẽ được coi là giá trị baseURL và chuỗi đầu tiên sẽ được đánh giá là tương ứng với cơ sở đó.

const p = new URLPattern({
  pathname: '/foo/:image.jpg',
  baseURL: 'https://example.com',
});

const result = p.exec('https://example.com/foo/cat.jpg');
// result will contain info about the successful match.
// const result = p.exec('/foo/cat.jpg', 'https://example.com')
// is equivalent, using the baseURL syntax.

const noMatchResult = p.exec('https://example.com/bar');
// noMatchResult will be null.

Ngoài ra, bạn có thể truyền cùng một loại đối tượng mà hàm khởi tạo hỗ trợ, với các thuộc tính chỉ được đặt cho các phần của URL mà bạn muốn so khớp.

const p = new URLPattern({pathname: '/foo/:image.jpg'});

const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.

Khi sử dụng exec() trên URLPattern chứa ký tự đại diện hoặc mã thông báo, giá trị trả về sẽ cung cấp cho bạn thông tin về các giá trị tương ứng trong URL nhập vào. Việc này có thể giúp bạn không phải tự phân tích cú pháp các giá trị đó.

const p = new URLPattern({
  hostname: ':subdomain.example.com',
  pathname: '/*/:image.jpg'
});

const result = p.exec('https://imagecdn1.example.com/foo/cat.jpg');
// result.hostname.groups.subdomain will be 'imagecdn1'
// result.pathname.groups[0] will be 'foo', corresponding to *
// result.pathname.groups.image will be 'cat'

Nhóm ẩn danh và được đặt tên

Khi truyền một chuỗi URL đến exec(), bạn sẽ nhận lại một giá trị cho biết phần nào khớp với tất cả nhóm mẫu.

Giá trị trả về có các thuộc tính tương ứng với các thành phần của URLPattern, chẳng hạn như pathname. Vì vậy, nếu một nhóm được xác định là một phần của phần pathname của URLPattern, thì bạn có thể tìm thấy các kết quả trùng khớp trong pathname.groups của giá trị trả về. Các kết quả trùng khớp được biểu thị theo cách khác nhau, tuỳ thuộc vào việc mẫu tương ứng là nhóm ẩn danh hay nhóm được đặt tên.

Bạn có thể sử dụng chỉ mục mảng để truy cập các giá trị cho kết quả khớp mẫu ẩn danh. Nếu có nhiều mẫu ẩn danh, chỉ mục 0 sẽ biểu thị giá trị phù hợp của mẫu ở ngoài cùng bên trái, với 1 và các chỉ mục khác được dùng cho các mẫu tiếp theo.

Khi sử dụng nhóm được đặt tên trong một mẫu, các kết quả trùng khớp sẽ hiển thị dưới dạng thuộc tính có tên tương ứng với từng tên nhóm.

Hỗ trợ và chuẩn hoá Unicode

URLPattern hỗ trợ các ký tự Unicode theo một số cách.

  • Các nhóm được đặt tên, chẳng hạn như :café, có thể chứa các ký tự Unicode. Các quy tắc dùng cho giá trị nhận dạng JavaScript hợp lệ sẽ áp dụng cho các nhóm được đặt tên.

  • Văn bản trong một mẫu sẽ tự động được mã hoá theo cùng các quy tắc dùng để mã hoá URL của thành phần cụ thể đó. Các ký tự Unicode trong pathname sẽ được mã hoá phần trăm, do đó, mẫu pathname như /café sẽ được chuẩn hoá thành /caf%C3%A9 tự động. Các ký tự Unicode trong hostname được tự động mã hoá bằng cách sử dụng Punycode, thay vì mã hoá phần trăm.

  • Nhóm biểu thức chính quy chỉ được chứa các ký tự ASCII. Cú pháp biểu thức chính quy gây khó khăn và không an toàn khi tự động mã hoá các ký tự Unicode trong các nhóm này. Nếu muốn so khớp một ký tự Unicode trong một nhóm biểu thức chính quy, bạn cần mã hoá phần trăm đó theo cách thủ công, chẳng hạn như (caf%C3%A9) để khớp với café.

Ngoài việc mã hoá các ký tự Unicode, URLPattern cũng chuẩn hoá URL. Ví dụ: /foo/./bar trong thành phần pathname sẽ được thu gọn thành /foo/bar tương đương.

Khi nghi ngờ về cách một mẫu đầu vào nhất định đã được chuẩn hoá, hãy kiểm tra thực thể URLPattern đã tạo bằng DevTools của trình duyệt.

Kết hợp kiến thức đã học

Bản minh hoạ sự cố trục trặc mã được nhúng bên dưới minh hoạ một trường hợp sử dụng cốt lõi của URLPattern bên trong fetch event handler của trình chạy dịch vụ, liên kết các mẫu cụ thể đến các hàm không đồng bộ có thể tạo phản hồi cho các yêu cầu mạng. Bạn cũng có thể áp dụng các khái niệm trong ví dụ này cho các trường hợp định tuyến khác, phía máy chủ hoặc phía máy khách.

Ý kiến phản hồi và kế hoạch trong tương lai

Mặc dù chức năng cơ bản của URLPattern đã được cung cấp cho Chrome và Edge, nhưng chúng tôi đã lên kế hoạch bổ sung cho Chrome và Edge. Một số khía cạnh của URLPattern vẫn đang được phát triển và có một số câu hỏi mở về các hành vi cụ thể vẫn có thể được tinh chỉnh. Bạn nên dùng thử URLPattern và cung cấp ý kiến phản hồi qua vấn đề trên GitHub.

Hỗ trợ tạo mẫu

Thư viện path-to-regexp cung cấp một compile() function giúp đảo ngược hành vi định tuyến một cách hiệu quả. compile() lấy mẫu và giá trị cho phần giữ chỗ mã thông báo rồi trả về một chuỗi cho đường dẫn URL có các giá trị được thay thế.

Chúng tôi hy vọng có thể thêm API này vào URLPattern trong tương lai, nhưng nó không nằm trong phạm vi của bản phát hành ban đầu.

Cho phép các tính năng nền tảng web trong tương lai

Giả sử URLPattern trở thành một phần đã được thiết lập của nền tảng web, các tính năng khác có thể hưởng lợi từ việc định tuyến hoặc so khớp mẫu có thể được xây dựng dựa trên các tính năng ban đầu.

Hiện vẫn có các cuộc thảo luận về việc sử dụng URLPattern cho các tính năng được đề xuất như so khớp mẫu phạm vi trình chạy dịch vụ, PWA làm trình xử lý tệptìm nạp trước theo suy đoán.

Xác nhận

Hãy xem tài liệu giải thích gốc để biết danh sách đầy đủ các xác nhận.