Xuất bản: Ngày 22 tháng 7 năm 2021
Định tuyến là một phần quan trọng của mọi ứng dụng web. Về cơ bản, định tuyến sẽ lấy một URL, áp dụng tính năng so khớp mẫu hoặc logic dành riêng cho ứng dụng khác cho URL đó, rồi thường hiển thị nội dung web dựa trên kết quả. Bạn có thể triển khai định tuyến theo một số cách:
- Mã máy chủ liên kết các đường dẫn với các tệp trên đĩa
- Logic trong một ứng dụng một trang chờ các thay đổi đối với vị trí hiện tại, sau đó tạo và hiển thị một phần DOM tương ứng.
Mặc dù không có tiêu chuẩn nào là tiêu chuẩn xác định duy nhất, nhưng các nhà phát triển web đã hướng đến một cú pháp chung để thể hiện các mẫu định tuyến URL có nhiều điểm chung với regular expressions, nhưng có một số điểm bổ sung 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ổ biến phía máy chủ như Express và Ruby 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), đồng thời 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, được xây dựng 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à bộ sửa đổi nhóm. 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 thông thường, chẳng hạn như so khớp với URL đầy đủ hoặc pathname URL và trả về thông tin về mã thông báo và các kết quả so khớp theo nhóm.
Một lợi ích khác của việc cung cấp tính năng so khớp URL ngay trong nền tảng web là bạn có thể chia sẻ một 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 mà không có sự hỗ trợ tích hợp. Nếu bạn sử dụng đoạn mã polyfill, hãy đảm bảo rằng bạn sử dụng tính năng phát hiện để đảm bảo rằng bạn chỉ tải đoạn mã này 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: đó là môi trường hỗ trợ không cần 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ý chỉ đạo 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 dùng trong Express hoặc Ruby on Rails, bạn sẽ không phải học thêm điều gì mới. Nhưng do có một số điểm 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 cần phải chọn một cú pháp làm cú pháp cơ sở và 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 cú pháp đó) làm điểm bắt đầu.
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 cho 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à một siêu tập hợp 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 số các thư viện định tuyến: so khớp nguồn, 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 search hoặc hash của một URL. Chúng 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 cho hoạt động định tuyến cùng nguồn gốc trong một ứng dụng web độc lập.
Việc xem xét nguồn gốc sẽ mở 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 service worker. 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 một URLPattern, hãy truyền cho hàm khởi tạo của nó 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 mang lại khả năng kiểm soát rõ ràng nhất đối với mẫu cần sử dụng để so khớp từng thành phần URL. Ở chế độ chi tiết nhất, thông tin này có thể trô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 thuộc tính sẽ chỉ khớp nếu phần tương ứng của URL chưa được đặt. Ký tự đại diện * sẽ khớp với mọi giá trị cho một phần nhất định của URL.
Trình khởi tạo cung cấp một số phím tắt để sử dụng đơn giản hơn. Việc hoàn toàn bỏ qua search và hash hoặc bất kỳ thuộc tính nào khác tương đương với việc đặt chúng thành ký tự đại diện '*'. Bạn có thể đơn giản hoá ví dụ này thành:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
Là 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, baseURL, dẫn đến
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
Tất cả cá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 các nguồn trùng khớp. Nếu chỉ quan tâm đến việc so khớp các phần khác của URL, ngoại trừ nguồn gốc (như trong trường hợp của nhiều kịch bản định tuyến một nguồn gốc), 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 thuộc tính pathname, search và hash. Như trước đây, các thuộc tính bị bỏ qua sẽ được coi như thể chúng đượ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, chuỗi đó phải biểu thị 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 2 chuỗi, chuỗi thứ hai sẽ được dùng làm baseURL và chuỗi đầu tiên được coi 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 đó thành các thành phần URL và ánh xạ từng phần của mẫu lớn hơn đến thành phần tương ứng. Điều này có nghĩa là ở bên dưới, 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 các chuỗi để tạo URLPattern, bạn cần lưu ý một số điểm sau.
Khi sử dụng một đối tượng để tạo URLPattern, việc bỏ qua một thuộc tính tương đương với việc cung cấp một 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 '', chỉ khớp khi thành phần đó trống.
Khi sử dụng các chuỗi, bạn cần phải thêm rõ ràng các ký tự đại diện nếu muốn sử dụng chúng 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ó những 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 trường hợp mơ hồ 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ẫ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 một chuỗi.
Dùng hình mở khoá
Sau khi tạo một URLPattern, bạn có 2 lựa chọn để sử dụng. Cả phương thức test() và 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ó trùng khớp hay không, đồng thời chỉ khác nhau về giá trị trả về. test() trả về true khi có kết quả trùng khớp cho dữ liệu đầu vào đã cho và trả về false trong các trường hợp khác.
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 minh hoạ cách sử dụng exec(), nhưng bạn có thể thay thế bằng test() cho bất kỳ ví dụ nào trong số này nếu chỉ muốn có giá trị trả về là boolean.
Một cách để sử dụng các phương thức test() và exec() là truyền vào các chuỗi.
Tương tự như những gì mà hàm khởi tạo hỗ trợ, nếu bạn cung cấp một chuỗi duy nhất, thì đó 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 đượ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 được đặt thành chỉ các 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 một URLPattern có 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ề 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á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 những 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 pathname trong URLPattern, thì các kết quả khớp có thể được tìm thấy 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 nhóm có 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 mẫu khớp ẩn danh.
Nếu có nhiều mẫu ẩn danh, chỉ mục 0 sẽ biểu thị giá trị trùng khớp cho 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 các ký tự Unicode. Các quy tắc đượ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ác quy tắc tương tự được dùng để mã hoá URL của thành phần cụ thể đó. Các ký tự Unicode trong
pathnamesẽ được mã hoá bằng phần trăm, vì vậy, một mẫupathnamenhư/cafésẽ tự động được chuẩn hoá thành/caf%C3%A9. Các ký tự Unicode tronghostnamesẽ tự động được mã hoá bằng Punycode thay vì mã hoá theo tỷ lệ phần trăm.Các 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á các 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 mã hoá ký tự đó theo tỷ lệ phần trăm theo cách thủ công, chẳng hạn như
(caf%C3%A9)để so khớpcafé.
Ngoài việc mã hoá các ký tự Unicode, URLPattern còn thực hiện 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 chuẩn hoá một mẫu đầu vào nhất định, hãy kiểm tra phiên bản 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 minh hoạ một trường hợp sử dụng cốt lõi của URLPattern trong fetch event handler của worker dịch vụ, ánh xạ các mẫu cụ thể đến các hàm không đồng bộ có thể tạo ra 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 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 cho URLPattern đã có trên 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 chưa được giải đáp về những hành vi cụ thể có thể vẫn đang được tinh chỉnh. Bạn nên dùng thử URLPattern và gửi mọi ý kiến phản hồi thông qua vấn đề trên GitHub.
Hỗ trợ việc tạo mẫu
Thư viện path-to-regexp cung cấp một compile() function giúp đả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 tính năng này vào URLPattern 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 ban đầu.
Bật các tính năng của nền tảng web trong tương lai
Giả sử URLPattern trở thành một phần cố định 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ể dựa vào tính năng này như một thành phần cơ bản.
Hiện đang 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 của worker dịch vụ, PWA dưới dạng trình xử lý tệp và tìm nạp trước mang tính suy đoá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.