định tuyến hộp công việc

Trình chạy dịch vụ có thể chặn các yêu cầu mạng cho một trang. Dịch vụ này có thể phản hồi trình duyệt bằng nội dung được lưu vào bộ nhớ đệm, nội dung từ mạng hoặc nội dung được tạo trong trình chạy dịch vụ.

workbox-routing là một mô-đun giúp bạn dễ dàng "định tuyến" những yêu cầu này đến các hàm cung cấp phản hồi.

Cách thực hiện việc định tuyến

Khi yêu cầu mạng gây ra một sự kiện tìm nạp trình chạy dịch vụ, workbox-routing sẽ cố gắng phản hồi yêu cầu bằng cách sử dụng các tuyến và trình xử lý đã cung cấp.

Sơ đồ định tuyến hộp công việc

Những điều chính cần lưu ý về những điều trên là:

  • Phương thức của yêu cầu rất quan trọng. Theo mặc định, Tuyến đường được đăng ký cho các yêu cầu GET. Nếu muốn chặn các loại yêu cầu khác, bạn cần chỉ định phương thức.

  • Thứ tự đăng ký Tuyến đường là quan trọng. Nếu bạn đăng ký nhiều Tuyến đường có thể xử lý một yêu cầu, thì Tuyến được đăng ký trước sẽ được dùng để phản hồi yêu cầu.

Có một số cách để đăng ký tuyến: bạn có thể dùng lệnh gọi lại, biểu thức chính quy hoặc thực thể Tuyến đường.

So khớp và xử lý trên tuyến đường

"Tuyến" trong hộp công việc chỉ có hai chức năng: hàm "phù hợp" để xác định xem tuyến có khớp với một yêu cầu và chức năng "xử lý" hay không. Hàm này sẽ xử lý yêu cầu và phản hồi bằng một phản hồi.

Workbox đi kèm với một số trình trợ giúp sẽ thực hiện việc so khớp và xử lý cho bạn, nhưng nếu bạn thấy mình muốn có hành vi khác, thì tốt nhất là viết hàm so khớp và trình xử lý tuỳ chỉnh.

Hàm callback so khớp được truyền ExtendableEvent, RequestURL đối tượng mà bạn có thể so khớp bằng cách trả về một giá trị trung thực. Ví dụ đơn giản, bạn có thể so khớp với một URL cụ thể như sau:

const matchCb = ({url, request, event}) => {
  return url.pathname === '/special/url';
};

Bạn có thể xử lý hầu hết các trường hợp sử dụng bằng cách kiểm tra / kiểm thử url hoặc request.

Hàm gọi lại trình xử lý sẽ được cung cấp cùng một ExtendableEvent, RequestURL đối tượng cùng với giá trị params. Đây là giá trị được hàm "match" trả về.

const handlerCb = async ({url, request, event, params}) => {
  const response = await fetch(request);
  const responseBody = await response.text();
  return new Response(`${responseBody} <!-- Look Ma. Added Content. -->`, {
    headers: response.headers,
  });
};

Trình xử lý của bạn phải trả về một lời hứa phân giải thành Response. Trong ví dụ này, chúng tôi sẽ sử dụng asyncawait. Trong trường hợp này, giá trị trả về Response sẽ được gói trong một lời hứa.

Bạn có thể đăng ký các lệnh gọi lại này như sau:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb);

Hạn chế duy nhất là lệnh gọi lại "match" (khớp) phải đồng bộ trả về một giá trị đáng tin cậy, bạn không thể thực hiện bất kỳ thao tác không đồng bộ nào. Lý do là vì Router phải phản hồi đồng bộ sự kiện tìm nạp hoặc cho phép chuyển sang các sự kiện tìm nạp khác.

Thông thường, lệnh gọi lại "xử lý" sẽ sử dụng một trong các chiến lược do chiến lược hộp công việc cung cấp như sau:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';

registerRoute(matchCb, new StaleWhileRevalidate());

Trên trang này, chúng ta sẽ tập trung vào workbox-routing. Tuy nhiên, bạn có thể tìm hiểu thêm về các chiến lược này trong các chiến lược hộp công việc.

Cách đăng ký tuyến biểu thức chính quy

Một phương pháp phổ biến là sử dụng biểu thức chính quy thay vì lệnh gọi lại "khớp". Workbox giúp bạn dễ dàng triển khai như sau:

import {registerRoute} from 'workbox-routing';

registerRoute(new RegExp('/styles/.*\\.css'), handlerCb);

Đối với các yêu cầu từ cùng một nguồn gốc, biểu thức chính quy này sẽ khớp, miễn là URL của yêu cầu khớp với biểu thức chính quy.

  • https://example.com/styles/main.css
  • https://example.com/styles/nested/file.css
  • https://example.com/nested/styles/directory.css

Tuy nhiên, đối với các yêu cầu nhiều nguồn gốc, biểu thức chính quy phải khớp với phần đầu của URL. Lý do là vì không có khả năng biểu thức chính quy new RegExp('/styles/.*\\.css') mà bạn định so khớp với các tệp CSS của bên thứ ba.

  • https://cdn.third-party-site.com/styles/main.css
  • https://cdn.third-party-site.com/styles/nested/file.css
  • https://cdn.third-party-site.com/nested/styles/directory.css

Nếu đã muốn có hành vi này, bạn chỉ cần đảm bảo rằng biểu thức chính quy khớp với phần đầu của URL. Nếu muốn so khớp các yêu cầu cho https://cdn.third-party-site.com, chúng ta có thể sử dụng biểu thức chính quy new RegExp('https://cdn\\.third-party-site\\.com.*/styles/.*\\.css').

  • https://cdn.third-party-site.com/styles/main.css
  • https://cdn.third-party-site.com/styles/nested/file.css
  • https://cdn.third-party-site.com/nested/styles/directory.css

Nếu muốn so khớp cả bên cục bộ và bên thứ ba, bạn có thể sử dụng ký tự đại diện ở đầu biểu thức chính quy, nhưng bạn nên thận trọng khi thực hiện để đảm bảo không gây ra các hành vi không mong muốn trong ứng dụng web của mình.

Cách đăng ký tuyến điều hướng

Nếu trang web của bạn là ứng dụng trang đơn, bạn có thể dùng NavigationRoute để trả về một phản hồi cụ thể cho tất cả yêu cầu điều hướng.

import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler);
registerRoute(navigationRoute);

Bất cứ khi nào người dùng truy cập vào trang web của bạn trong trình duyệt, yêu cầu đối với trang sẽ là một yêu cầu điều hướng và sẽ được phân phát đến trang đã lưu trong bộ nhớ đệm /app-shell.html. (Lưu ý: Bạn nên lưu trang vào bộ nhớ đệm qua workbox-precaching hoặc qua bước cài đặt của riêng bạn.)

Theo mặc định, thao tác này sẽ phản hồi tất cả các yêu cầu chỉ đường. Nếu muốn hạn chế URL này phản hồi một nhóm nhỏ URL, bạn có thể sử dụng các tuỳ chọn allowlistdenylist để hạn chế những trang sẽ khớp với tuyến này.

import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
  allowlist: [new RegExp('/blog/')],
  denylist: [new RegExp('/blog/restricted/')],
});
registerRoute(navigationRoute);

Điều duy nhất cần lưu ý là denylist sẽ thắng nếu một URL nằm trong cả allowlistdenylist.

Đặt trình xử lý mặc định

Nếu muốn cung cấp "trình xử lý" cho các yêu cầu không khớp với tuyến đường, bạn có thể đặt trình xử lý mặc định.

import {setDefaultHandler} from 'workbox-routing';

setDefaultHandler(({url, event, params}) => {
  // ...
});

Thiết lập Trình xử lý bắt (catch Handler)

Trong trường hợp bất kỳ tuyến nào của bạn gặp lỗi, bạn có thể nắm bắt và xuống cấp nhẹ bằng cách thiết lập trình xử lý phát hiện.

import {setCatchHandler} from 'workbox-routing';

setCatchHandler(({url, event, params}) => {
  ...
});

Xác định tuyến cho các yêu cầu không GET

Tất cả các tuyến theo mặc định đều được giả định là dành cho các yêu cầu GET.

Nếu muốn định tuyến các yêu cầu khác, chẳng hạn như yêu cầu POST, bạn cần xác định phương thức khi đăng ký tuyến, như sau:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb, 'POST');
registerRoute(new RegExp('/api/.*\\.json'), handlerCb, 'POST');

Ghi nhật ký bộ định tuyến

Bạn có thể xác định luồng yêu cầu bằng cách sử dụng nhật ký từ workbox-routing, nhật ký này sẽ làm nổi bật URL nào đang được xử lý thông qua Workbox.

Nhật ký định tuyến

Nếu cần thông tin chi tiết hơn, bạn có thể đặt cấp độ nhật ký thành debug để xem nhật ký về các yêu cầu không do Bộ định tuyến xử lý. Xem hướng dẫn gỡ lỗi của chúng tôi để biết thêm thông tin về cách đặt cấp độ nhật ký.

Thông báo gỡ lỗi và ghi nhật ký định tuyến

Cách sử dụng nâng cao

Nếu muốn có thêm quyền kiểm soát đối với thời điểm Bộ định tuyến Workbox được đưa ra yêu cầu, bạn có thể tạo thực thể Router riêng và gọi phương thức handleRequest() của nó bất cứ khi nào bạn muốn dùng bộ định tuyến để phản hồi yêu cầu.

import {Router} from 'workbox-routing';

const router = new Router();

self.addEventListener('fetch', event => {
  const {request} = event;
  const responsePromise = router.handleRequest({
    event,
    request,
  });
  if (responsePromise) {
    // Router found a route to handle the request.
    event.respondWith(responsePromise);
  } else {
    // No route was found to handle the request.
  }
});

Khi sử dụng trực tiếp Router, bạn cũng cần dùng lớp Route hoặc bất kỳ lớp mở rộng nào để đăng ký các tuyến.

import {Route, RegExpRoute, NavigationRoute, Router} from 'workbox-routing';

const router = new Router();
router.registerRoute(new Route(matchCb, handlerCb));
router.registerRoute(new RegExpRoute(new RegExp(...), handlerCb));
router.registerRoute(new NavigationRoute(handlerCb));

Loại

NavigationRoute

NavigationRoute giúp bạn dễ dàng tạo workbox-routing.Route phù hợp với [các yêu cầu điều hướng]https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests của trình duyệt.

Thao tác này sẽ chỉ so khớp các Yêu cầu đến có https://fetch.spec.whatwg.org/#concept-request-mode|mode được đặt thành navigate.

Bạn có thể tuỳ ý chỉ áp dụng tuyến này cho một nhóm nhỏ yêu cầu điều hướng bằng cách sử dụng một hoặc cả hai tham số denylistallowlist.

Thuộc tính

  • hàm khởi tạo

    void

    Nếu bạn cung cấp cả denylistallowlist, thì denylist sẽ được ưu tiên và yêu cầu sẽ không khớp với tuyến này.

    Biểu thức chính quy trong allowlistdenylist được so khớp với các phần đã nối [pathname]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname và [search]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search của URL được yêu cầu.

    Lưu ý: Bạn có thể đánh giá các biểu thức chính quy này dựa trên mọi URL đích trong quá trình điều hướng. Tránh sử dụng biểu thức chính quy phức tạp, nếu không người dùng có thể thấy độ trễ khi di chuyển trên trang web của bạn.

    Hàm constructor sẽ có dạng như sau:

    (handler: RouteHandler,options?: NavigationRouteMatchOptions)=> {...}

  • catchHandler

    RouteHandlerObject không bắt buộc

  • trình xử lý
  • phù hợp
  • method

    HTTPMethod

  • setCatchHandler

    void

    Hàm setCatchHandler sẽ có dạng như sau:

    (handler: RouteHandler)=> {...}

    • trình xử lý

      Một hàm callback trả về một Hứa hẹn sẽ giải quyết một Phản hồi

NavigationRouteMatchOptions

Thuộc tính

  • danh sách cho phép

    RegExp[] không bắt buộc

  • danh sách từ chối

    RegExp[] không bắt buộc

RegExpRoute

RegExpRoute giúp bạn dễ dàng tạo biểu thức chính quy dựa trên workbox-routing.Route.

Đối với các yêu cầu có cùng nguồn gốc, RegExp chỉ cần khớp với một phần của URL. Đối với các yêu cầu dựa trên máy chủ của bên thứ ba, bạn phải xác định một biểu thức chính quy khớp với phần đầu của URL.

Thuộc tính

  • hàm khởi tạo

    void

    Nếu biểu thức chính quy chứa [capture groups]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references, các giá trị được thu thập sẽ được chuyển đến đối số workbox-routing~handlerCallback params.

    Hàm constructor sẽ có dạng như sau:

    (regExp: RegExp,handler: RouteHandler,method?: HTTPMethod)=> {...}

    • regExp

      RegExp

      Biểu thức chính quy để so khớp với URL.

    • trình xử lý

      Một hàm callback trả về một Promise dẫn đến một Response.

    • method

      HTTPMethod không bắt buộc

  • catchHandler

    RouteHandlerObject không bắt buộc

  • trình xử lý
  • phù hợp
  • method

    HTTPMethod

  • setCatchHandler

    void

    Hàm setCatchHandler sẽ có dạng như sau:

    (handler: RouteHandler)=> {...}

    • trình xử lý

      Một hàm callback trả về một Hứa hẹn sẽ giải quyết một Phản hồi

Route

Route bao gồm một cặp hàm callback, "match" và "handler". Lệnh gọi lại "match" (so khớp) xác định xem có nên sử dụng một tuyến để "xử lý" yêu cầu bằng cách trả về một giá trị không giả mạo nếu có thể. Lệnh gọi lại "handler" được gọi khi có kết quả trùng khớp và sẽ trả về một Promise giải quyết thành Response.

Thuộc tính

  • hàm khởi tạo

    void

    Hàm khởi tạo cho lớp Tuyến đường.

    Hàm constructor sẽ có dạng như sau:

    (match: RouteMatchCallback,handler: RouteHandler,method?: HTTPMethod)=> {...}

    • phù hợp

      Hàm callback xác định xem tuyến có khớp với một sự kiện fetch nhất định hay không bằng cách trả về một giá trị không giả.

    • trình xử lý

      Một hàm callback trả về một Hứa hẹn sẽ phân giải một Phản hồi.

    • method

      HTTPMethod không bắt buộc

  • catchHandler

    RouteHandlerObject không bắt buộc

  • trình xử lý
  • phù hợp
  • method

    HTTPMethod

  • setCatchHandler

    void

    Hàm setCatchHandler sẽ có dạng như sau:

    (handler: RouteHandler)=> {...}

    • trình xử lý

      Một hàm callback trả về một Hứa hẹn sẽ giải quyết một Phản hồi

Router

Bạn có thể dùng Bộ định tuyến để xử lý FetchEvent bằng một hoặc nhiều workbox-routing.Route, phản hồi bằng Response nếu có một tuyến trùng khớp.

Nếu không có tuyến nào khớp với một yêu cầu nhất định, thì Bộ định tuyến sẽ sử dụng trình xử lý "mặc định" nếu có một trình xử lý được xác định.

Nếu Tuyến đường trùng khớp báo lỗi, Bộ định tuyến sẽ sử dụng trình xử lý "catch" nếu bạn xác định trình xử lý này là để xử lý vấn đề linh hoạt và phản hồi bằng một Yêu cầu.

Nếu một yêu cầu khớp với nhiều tuyến, thì tuyến đã đăng ký sớm nhất sẽ được dùng để phản hồi yêu cầu.

Thuộc tính

  • hàm khởi tạo

    void

    Khởi chạy Bộ định tuyến mới.

    Hàm constructor sẽ có dạng như sau:

    ()=> {...}

  • tuyến đường

    Map<HTTPMethodRoute[]>

  • addCacheListener

    void

    Thêm trình nghe sự kiện thông báo cho các URL vào bộ nhớ đệm từ cửa sổ. Việc này rất hữu ích khi lưu các tài nguyên được tải trên trang vào bộ nhớ đệm trước khi trình chạy dịch vụ bắt đầu kiểm soát tài nguyên đó.

    Định dạng của dữ liệu thư gửi từ cửa sổ như sau. Trong đó, mảng urlsToCache có thể bao gồm chuỗi URL hoặc một mảng gồm chuỗi URL + đối tượng requestInit (tương tự như cách bạn truyền đến fetch()).

    {
      type: 'CACHE_URLS',
      payload: {
        urlsToCache: [
          './script1.js',
          './script2.js',
          ['./script3.js', {mode: 'no-cors'}],
        ],
      },
    }
    

    Hàm addCacheListener sẽ có dạng như sau:

    ()=> {...}

  • addFetchListener

    void

    Thêm trình nghe sự kiện tìm nạp để phản hồi các sự kiện khi một tuyến khớp với yêu cầu của sự kiện.

    Hàm addFetchListener sẽ có dạng như sau:

    ()=> {...}

  • findMatchingRoute

    void

    Kiểm tra yêu cầu và URL (và không bắt buộc là một sự kiện) dựa trên danh sách tuyến đã đăng ký và nếu có kết quả trùng khớp, hãy trả về tuyến tương ứng cùng với mọi tham số do kết quả so khớp tạo ra.

    Hàm findMatchingRoute sẽ có dạng như sau:

    (options: RouteMatchCallbackOptions)=> {...}

    • giá trị trả về

      đối tượng

      Một đối tượng có các thuộc tính routeparams. Các giá trị này được điền sẵn nếu tìm thấy một tuyến đường trùng khớp hoặc undefined nếu không.

  • handleRequest

    void

    Áp dụng các quy tắc định tuyến cho một đối tượng FetchEvent để nhận được Phản hồi từ trình xử lý của Tuyến đường thích hợp.

    Hàm handleRequest sẽ có dạng như sau:

    (options: object)=> {...}

    • tùy chọn

      đối tượng

      • event

        ExtendableEvent

        Sự kiện đã kích hoạt yêu cầu.

      • request

        Yêu cầu

        Yêu cầu được xử lý.

    • giá trị trả về

      Hứa hẹn<Phản hồi>

      Một lời hứa sẽ được trả về nếu một tuyến đã đăng ký có thể xử lý yêu cầu. Nếu không có tuyến đường nào trùng khớp và không có defaultHandler, thì undefined sẽ được trả về.

  • registerRoute

    void

    Đăng ký một tuyến với bộ định tuyến.

    Hàm registerRoute sẽ có dạng như sau:

    (route: Route)=> {...}

  • setCatchHandler

    void

    Nếu một Tuyến đường báo lỗi trong khi xử lý yêu cầu, thì handler này sẽ được gọi và cung cấp cơ hội phản hồi.

    Hàm setCatchHandler sẽ có dạng như sau:

    (handler: RouteHandler)=> {...}

    • trình xử lý

      Một hàm callback trả về một Promise dẫn đến một Response.

  • setDefaultHandler

    void

    Xác định handler mặc định sẽ được gọi khi không có tuyến nào khớp rõ ràng với yêu cầu đến.

    Mỗi phương thức HTTP ('GET', 'POST', v.v.) đều có trình xử lý mặc định riêng.

    Nếu không có trình xử lý mặc định, các yêu cầu chưa khớp sẽ truy cập vào mạng như thể không có trình chạy dịch vụ nào.

    Hàm setDefaultHandler sẽ có dạng như sau:

    (handler: RouteHandler,method?: HTTPMethod)=> {...}

    • trình xử lý

      Một hàm callback trả về một Promise dẫn đến một Response.

    • method

      HTTPMethod không bắt buộc

  • unregisterRoute

    void

    Huỷ đăng ký một tuyến đường với bộ định tuyến.

    Hàm unregisterRoute sẽ có dạng như sau:

    (route: Route)=> {...}

Phương thức

registerRoute()

workbox-routing.registerRoute(
  capture: string|RegExp|RouteMatchCallback|Route,
  handler?: RouteHandler,
  method?: HTTPMethod,
)

Dễ dàng đăng ký RegExp, chuỗi hoặc hàm bằng chiến lược lưu vào bộ nhớ đệm cho một thực thể Bộ định tuyến singleton.

Phương thức này sẽ tạo một Tuyến đường cho bạn nếu cần và gọi workbox-routing.Router#registerRoute.

Tham số

  • chụp

    Nếu tham số chụp là Route, thì tất cả các đối số khác sẽ bị bỏ qua.

  • trình xử lý

    RouteHandler không bắt buộc

  • method

    HTTPMethod không bắt buộc

Giá trị trả về

setCatchHandler()

workbox-routing.setCatchHandler(
  handler: RouteHandler,
)

Nếu một Tuyến đường báo lỗi trong khi xử lý yêu cầu, thì handler này sẽ được gọi và cung cấp cơ hội phản hồi.

Tham số

  • trình xử lý

    Một hàm callback trả về một Promise dẫn đến một Response.

setDefaultHandler()

workbox-routing.setDefaultHandler(
  handler: RouteHandler,
)

Xác định handler mặc định sẽ được gọi khi không có tuyến nào khớp rõ ràng với yêu cầu đến.

Nếu không có trình xử lý mặc định, các yêu cầu chưa khớp sẽ truy cập vào mạng như thể không có trình chạy dịch vụ nào.

Tham số

  • trình xử lý

    Một hàm callback trả về một Promise dẫn đến một Response.