pwa на Chrome Mobile продолжает возвращать только кэшированную версию http-ответов данных

#angular #caching #service-worker #progressive-web-apps #mobile-chrome

#angular #кэширование #service-worker #progressive-веб-приложения #mobile-chrome

Вопрос:

У меня есть веб-приложение Angular 7 Progressive (PWA, Service Worker).

Мое приложение выполняет http-запросы к api для получения данных для страницы. с помощью service worker я кэширую данные, чтобы при следующем входе пользователя на страницу он видел кэшированные данные, пока не получит последние данные из http-ответа.

Проблема в Chrome Mobile на Android. Он продолжает возвращать только кэшированный http-ответ, а не новые данные. Все остальные браузеры и ОС возвращают новые данные.

Вот мой файл ngsw.json:

 {
  "configVersion": 1,
  "timestamp": 1553131016147,
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "updateMode": "prefetch",
      "urls": [
        "/favicon.ico",
        "/index.html",
        "/main.888b10bbc9ea06b8a9bf.js",
        "/polyfills.9f595158f842acad6b37.js",
        "/runtime.2f29e12616932f0ed037.js",
        "/styles.d2478451b17ed7e705c5.css"
      ],
      "patterns": []
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "urls": [],
      "patterns": [
        "https:\/\/maxcdn\.bootstrapcdn\.com\/font-awesome\/4\.7\.0\/css\/font-awesome\.min\.css"
      ]
    }
  ],
  "dataGroups": [
    {
      "name": "api",
      "patterns": [
        "\/api"
      ],
      "strategy": "freshness",
      "maxSize": 100,
      "maxAge": 259200000,
      "timeoutMs": 5000,
      "version": 1
    }
  ],
  "hashTable": {
    "/favicon.ico": "7c6a9b4e1370b6ee9386e16fba9ca4738b9e7037",
    "/index.html": "fdf70f70c0f37aaa11b990ac0cf32839480b69a4",
    "/main.888b10bbc9ea06b8a9bf.js": "abcc804a2ffbd57187d759a7c18b82963ac03d8c",
    "/polyfills.9f595158f842acad6b37.js": "4eb96258211620bfe371478144b69844117f5120",
    "/runtime.2f29e12616932f0ed037.js": "21109b3561b5a6c3ed51bc3015962f05da8e57b3",
    "/styles.d2478451b17ed7e705c5.css": "29fb80dd9fc36fbb4ee107f15fd24dd7400ea255"
  },
  "navigationUrls": [
    {
      "positive": true,
      "regex": "^\/.*$"
    },
    {
      "positive": false,
      "regex": "^\/(?:. \/)?[^/]*\.[^/]*$"
    },
    {
      "positive": false,
      "regex": "^\/(?:. \/)?[^/]*__[^/]*$"
    },
    {
      "positive": false,
      "regex": "^\/(?:. \/)?[^/]*__[^/]*\/.*$"
    }
  ]
}
 

Соответствующая часть кода находится в разделе DataGroups, все URL-адреса с /api префиксом, и, как вы можете видеть, я использую freshness стратегию, которая в соответствии со страницей конфигурации Angular Service worker:
https://angular.io/guide/service-worker-config

свежесть оптимизирует валюту данных, предпочтительно извлекая запрошенные данные из сети. Только если время ожидания сети истекло, в соответствии с таймаутом, запрос возвращается в кэш. Это полезно для ресурсов, которые часто меняются; например, остатки на счетах.

но, похоже, в этом случае с Chrome Mobile на Android происходит обратное.

Кто-нибудь из вас сталкивался с этим и может указать мне правильное направление?

Ответ №1:

Из того, что я понимаю о том, как работают работники службы angular,:

Если вы указали freshness стратегию, то сервисный работник будет ждать ответа сети в течение времени, указанного с timeout помощью ключа (не тайм-аута). если сеть не отвечает в течение указанного времени, ответ будет отправлен из кэшированных данных сервисным работником.

В вашем случае на устройстве Android может быть меньше скорость Интернета, поэтому данные не извлекаются в течение указанного интервала ожидания, поэтому вы получаете кэшированные данные. Проверьте приложение, увеличив время ожидания.


На всякий случай, если вам это нужно.

Я обнаружил, что запросы API кеширования очень ненадежны, у меня не было четкого представления, когда я точно получу обновленные данные. (Да, когда maxSize или maxAge превышают указанные значения или время ожидания превышено, но по-прежнему нет четкого способа, которым я мог бы точно получить свежие данные.).

Всякий раз, когда я хотел получить свежие данные с сервера, я очищал все кэшированные данные из браузера, которые принадлежали ngsw вызовам api. У меня был этот скрипт, написанный для того же. Посмотрите, если вам это нужно.

 caches.keys().then((keys) => {
    keys.forEach((eachCacheName) => {
        let regExPat = /^(ngsw).*api.*/;
        if (regExPat.test(eachCacheName)) {
            caches.open(eachCacheName).then((eachCache) => {
                eachCache.keys().then((requests) => {
                    requests.forEach((eachRequest) => { eachCache.delete(eachRequest); });
                });
            });
        }
    });
});
 

Комментарии:

1. текущий тайм-аут, который я использую, составляет 5 секунд, а среднее время отклика http, которое я получаю для вызовов API, составляет 250 мс, что составляет менее 5 секунд … а также страница завершает загрузку с кэшированными данными менее чем за 1 секунду, похоже, она ничего не ждет 5 секунд.

2. @shahaf Хорошо, у меня просто был какой-то шарнир, и это было только предположение. Я не знаю, что может быть причиной этого. Попробуйте открыть браузер в режиме инкогнито и посмотреть, есть ли какие-либо улучшения.