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

Một phương pháp để chuẩn hoá các trường hợp sử dụng phổ biến của việc so khớp mẫu.

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 liên quan đến việc lấy một URL, áp dụng một số kiểu so khớp mẫu hoặc logic dành riêng cho ứng dụng khác cho URL đó, sau đó thường hiển thị nội dung web dựa trên kết quả. Bạn có thể triển khai tính năng định tuyến theo một số cách: đôi khi là mã chạy trên máy chủ liên kết một đường dẫn đến các tệp trên ổ đĩa hoặc logic trong một ứng dụng một trang 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ó một tiêu chuẩn rõ ràng nào, nhưng các nhà phát triển web đã chuyển sang một cú pháp chung để biểu thị các mẫu định tuyến URL có nhiều điểm chung với regular expressions, nhưng có thêm một số thành phần dành riêng cho miền như mã thông báo để so khớp các phân đoạn đường dẫn. 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 cú pháp này) và các 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 phần bổ sung cho nền tảng web dựa trên nền tảng do các khung này tạo ra. Mục tiêu của nó là chuẩn hoá cú pháp mẫu định tuyến, bao gồm cả việc hỗ trợ ký tự đại diện, nhóm mã thông báo được đặt 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 URL đầy đủ hoặc URL pathname và trả về thông tin về mã thông báo và nhóm so 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 trong nền tảng web là sau đó, bạn có thể chia sẻ cú pháp chung với các API khác cũng cần so khớp với URL.

Hỗ trợ trình duyệt và 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ư Node thiếu tính năng hỗ trợ tích hợp. Nếu bạn sử dụng polyfill, hãy đảm bảo rằng bạn sử dụng tính 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 hỗ trợ. Nếu không, bạn sẽ mất một trong những lợi ích chính của URLPattern: 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

Triết lý hướng dẫn cho URLPattern là tránh việc phát minh lại. Nếu đã quen thuộc với cú pháp định tuyến được sử dụng trong Express hoặc Ruby on Rails, bạn sẽ không phải tìm hiểu thêm gì. 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, nên phải chọn một cú pháp làm cú pháp cơ sở. Các nhà thiết kế của URLPattern đã quyết định sử dụng cú pháp mẫu từ path-to-regexp (mặc dù không phải là giao diện API của thư viện này) làm điểm xuất phát.

Quyết định này được đưa ra sau khi tham khảo ý kiến của người duy trì hiện tại của path-to-regexp.

Cách tốt nhất để làm quen với 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ự kiến xuất bản trên MDN tại trang chủ hiện tại của tài liệu đó trên GitHub.

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

Cú pháp của URLPattern là tập hợp con của những gì path-to-regexp hỗ trợ, vì URLPattern hỗ trợ một tính năng không phổ biến trong 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ý pathname và đôi khi là phần tìm kiếm hoặc hàm băm của URL. Các ứng dụng này không bao giờ phải kiểm tra phần nguồ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 tính đến nguồn gốc sẽ mở ra nhiều 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ùng nguồn gốc, bạn có thể bỏ qua tính năng bổ sung này một cách hiệu quả 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 đối tượng này là các chuỗi hoặc một đối tượng có các thuộc tính chứa thông tin về mẫu cần so khớp.

Việc truyền một đối tượng sẽ cung cấp quyền kiểm soát rõ ràng nhất về mẫu cần sử dụng để khớp với từng thành phần URL. Ở mức chi tiết nhất, mã này có thể có dạng như sau

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 cơ sở lưu trú sẽ chỉ khớp nếu bạn không đặt phần tương ứng của URL. Ký tự đại diện * sẽ khớp với bất kỳ giá trị nào cho một phần nhất định của URL.

Hàm khởi tạo cung cấp một số phím 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 tương đương với việc đặt các thuộc tính đó 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',
});

Ngoài ra, bạn có thể cung cấp tất cả thông tin về nguồn gốc 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 liên quan đến việc so khớp nguồn gốc. Nếu chỉ quan tâm đến việc so khớp trên các phần khác của URL, ngoại trừ nguồn gốc (như trong nhiều trường hợp định tuyến nguồn gốc "truyền thống"), thì bạn có thể bỏ qua hoàn toàn thông tin nguồn gốc và chỉ cung cấp một số tổ hợp của các thuộc tính pathname, searchhash. Giống như trước đây, các thuộc tính bị 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 vào 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, thì 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 để so khớp nguồn gốc. Nếu bạn cung cấp hai chuỗi, thì chuỗi thứ hai sẽ được dùng làm baseURL và chuỗi đầu tiên được xem xét 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 đó thành các thành phần URL và liên kết 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 lớp phủ, mỗi URLPattern được tạo bằng chuỗi sẽ được biểu thị giống như một URLPattern tương đương được tạo bằng đố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 bỏ qua một thuộc tính khi sử dụng đố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 bị thiếu giá trị, thì thành phần đó sẽ được coi như thể thuộc tính của thành phần được đặt thành ''. Giá trị này 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 sử dụng ký tự đại diện 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ẫu chuỗi thành các thành phần có thể gây nhầm lẫn. Có một số ký tự, chẳng hạn như :, xuất hiện trong URL nhưng cũng có ý nghĩa đặc biệt trong cú pháp so khớp mẫu. Để tránh sự mơ hồ này, hàm khởi tạo URLPattern giả định rằng bất kỳ ký tự đặc biệt nào trong số đó đều là một phần của mẫu, chứ không phải là một phần của URL. Nếu bạn muốn một ký tự không rõ ràng được diễn giải là một phần của URL, hãy nhớ 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ó hai cách để sử dụng. Phương thức test()exec() đều nhận 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 xem có khớp hay không, chỉ khác nhau 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 có kết quả trùng khớp. exec() trả về thông tin chi tiết về kết quả trùng khớp cùng với các 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 đây minh hoạ cách 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ị trả về boolean đơn giản.

Một cách để sử dụng các phương thức test()exec() là truyền vào các chuỗi. Tương tự như nội dung mà hàm khởi tạo hỗ trợ, nếu bạn cung cấp một chuỗi duy nhất, thì chuỗi đó phải là một URL đầy đủ, bao gồm cả nguồn gốc. Nếu bạn cung cấp hai chuỗi, thì chuỗi thứ hai sẽ được coi là giá trị baseURL và chuỗi đầu tiên sẽ được đánh giá 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 được đặt thành chỉ những phần của URL mà bạn quan tâm đến việc 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 đầu vào. Điều 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à nhóm có tên

Khi truyền một chuỗi URL đến exec(), bạn sẽ nhận được một giá trị cho biết phần nào khớp với tất cả các nhóm của 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à một nhóm ẩn danh hay được đặt tên.

Bạn có thể sử dụng chỉ mục mảng để truy cập vào các giá trị cho một kiểu so 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ị khớp với 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 các 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 các 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 ký tự Unicode. Các quy tắc dùng cho giá trị nhận dạng JavaScript hợp lệ á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 một 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á theo phần trăm, vì vậy, mẫu pathname như /café sẽ được tự động chuẩn hoá thành /caf%C3%A9. Các ký tự Unicode trong hostname được tự động mã hoá bằng Punycode thay vì mã hoá bằng 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 khiến việc tự động mã hoá ký tự Unicode trong các nhóm này trở nên khó khăn và không an toàn. 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 tự mã hoá ký tự đó theo tỷ lệ phần trăm, chẳng hạn như (caf%C3%A9) để so khớp với café.

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

Khi không chắc chắn về cách một mẫu đầu vào nhất định được chuẩn hoá, hãy kiểm tra bản sao 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ạ Glitch đượ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 worker dịch vụ, liên kết các mẫu cụ thể với 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. Các khái niệm trong ví dụ này cũng có thể được áp dụng cho các tình huống đị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 đưa vào Chrome và Edge, nhưng chúng tôi vẫn có kế hoạch bổ sung thêm. 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ể có thể vẫn còn được tinh chỉnh. Bạn nên dùng thử URLPattern và gửi ý 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 đảo ngược hiệu quả hành vi định tuyến. compile() lấy một mẫu và các giá trị cho phần giữ chỗ mã thông báo, đồng thờ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 URLPattern này vào trong tương lai, nhưng tính năng này không nằm trong phạm vi của bản phát hành đầu tiên.

Bật các tính năng trong tương lai của nền tảng web

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 đó dưới dạng một tính năng gốc.

Chúng tôi đang 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 trong phạm vi worker dịch vụ, PWAs làm trình xử lý tệptìm nạp trước suy đoán.

Lời cảm ơn

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