使用 Service Worker 的渐进式 Web 应用程序:如何仅缓存页面的静态(非数据库相关)部分?
Progressive web app using Service Worker: How to cache only static (non database dependent) parts of a page?
我有一个需要离线工作的网络应用程序 (PHP/Laravel)。该应用程序用于管理我称之为 客户 的一些人。我的问题涉及一个页面,仅包含 table 列出我们所有客户的内容。路径是 /clients
.
MySQL(在服务器上)和索引数据库(供离线使用)之间的同步工作正常,现在我必须缓存该页面的静态 HTML。我当前的方法缓存整个页面 ,包括来自服务器的客户端数据。但是,我不想缓存中 MySQL 的任何数据,因为当我离线时,我会从 Indexed DB 中获取所有数据。
这是我的简化版 offline-worker.js
:
var CACHE_NAME = 'app-cache';
var urlsToCache = [
'/clients'
];
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/offline-worker.js');
}
self.addEventListener('install', function(evt) {
evt.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
)
});
self.addEventListener('fetch', function(evt) {
evt.respondWith(
caches.match(evt.request)
.then(function(response) {
if (response)
return response;
var fetchRequest = evt.request.clone();
return fetch(fetchRequest).then(
function(response) {
if (!response || response.status != 200 || response.type != 'basic')
return response;
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(evt.request, responseToCache);
});
return response;
}
);
})
)
});
现在,我会在浏览器检测到数据离线时立即删除数据,但我宁愿从头开始缓存该页面的 'clean' version/template。这是 /clients
:
的完全简化版本
<h1>Our clients</h1>
<table>
<tr>
<td>Charles</td>
<td>Chaplin</td>
</tr>
<!-- Imagine many more rows of server generated data here.
I'd like to get rid of all rows before caching. -->
</table>
在没有来自 MySQL 的任何数据的情况下缓存 /clients
的最佳方法是什么?我知道浏览器看不到哪些页面元素来自服务器数据库,哪些是静态的。
如果我必须手动设置离线版本,那也没关系。我只需要知道如何在没有网络连接时告诉浏览器使用离线版本。
我会创建一个新的 url 路由 /clientsTemplate,您 return 只有模板。此模板存储在应用程序缓存中。
var CACHE_NAME = 'app-cache';
var urlsToCache = [
'/clientsTemplate'
];
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/offline-worker.js');
}
self.addEventListener('install', function(evt) {
evt.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
)
});
然后你可以按如下方式实现抓取:
self.addEventListener('fetch', function (event) {
event.respondWith(
fetch(event.request).then(function (response) {
//the url concatenate is a bit hacky, works only if you don't have any url params
return response || caches.match(event.request.url+"Template");
})
);
});
Stefs answer 显示了一个简单的解决方案,如果应用程序中的每个页面都有一个离线模式版本。到目前为止,我已经重写了获取事件的侦听器。这可能是仅缓存有限数量的离线模式页面的最简单方法。现在,只有一个这样的页面,/clients
。一些其他页面和资产的 'standard' 版本也被缓存。
var CACHE_NAME = 'app-cache';
var urlsToCache = [
'/offline/clients',
'/css/bootstrap.min.css',
'js/bootstrap.min.js',
'/'
];
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/offline-worker.js');
}
// Open cache and add URLs to be cached
self.addEventListener('install', function(evt) {
evt.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
)
});
// Define responses
self.addEventListener('fetch', function(event) {
var request = event.request;
event.respondWith(
// Try to get page from server
fetch(request).catch(function(error) {
// Request failed: Get page from cache
return caches.open('app-cache').then(function(cache) {
// There's an offline mode version for this page
if (request.url.indexOf('myapp.test/clients') > -1) {
return cache.match('offline/clients');
}
// Standard version is used even in offline mode
else {
return cache.match(request.url);
}
});
})
);
});
我会通过 JS 渲染动态部分(组件)。每个 JS 部分将通过 Ajax 接收它需要的数据。那么平时的HTML和JS就可以缓存起来,以后离线使用。一旦用户离线,service worker 就可以开始从 IndexedDB 而不是后端返回数据。缓存的 HTML 和 JS 也将由 service worker 提供。
我有一个需要离线工作的网络应用程序 (PHP/Laravel)。该应用程序用于管理我称之为 客户 的一些人。我的问题涉及一个页面,仅包含 table 列出我们所有客户的内容。路径是 /clients
.
MySQL(在服务器上)和索引数据库(供离线使用)之间的同步工作正常,现在我必须缓存该页面的静态 HTML。我当前的方法缓存整个页面 ,包括来自服务器的客户端数据。但是,我不想缓存中 MySQL 的任何数据,因为当我离线时,我会从 Indexed DB 中获取所有数据。
这是我的简化版 offline-worker.js
:
var CACHE_NAME = 'app-cache';
var urlsToCache = [
'/clients'
];
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/offline-worker.js');
}
self.addEventListener('install', function(evt) {
evt.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
)
});
self.addEventListener('fetch', function(evt) {
evt.respondWith(
caches.match(evt.request)
.then(function(response) {
if (response)
return response;
var fetchRequest = evt.request.clone();
return fetch(fetchRequest).then(
function(response) {
if (!response || response.status != 200 || response.type != 'basic')
return response;
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(evt.request, responseToCache);
});
return response;
}
);
})
)
});
现在,我会在浏览器检测到数据离线时立即删除数据,但我宁愿从头开始缓存该页面的 'clean' version/template。这是 /clients
:
<h1>Our clients</h1>
<table>
<tr>
<td>Charles</td>
<td>Chaplin</td>
</tr>
<!-- Imagine many more rows of server generated data here.
I'd like to get rid of all rows before caching. -->
</table>
在没有来自 MySQL 的任何数据的情况下缓存 /clients
的最佳方法是什么?我知道浏览器看不到哪些页面元素来自服务器数据库,哪些是静态的。
如果我必须手动设置离线版本,那也没关系。我只需要知道如何在没有网络连接时告诉浏览器使用离线版本。
我会创建一个新的 url 路由 /clientsTemplate,您 return 只有模板。此模板存储在应用程序缓存中。
var CACHE_NAME = 'app-cache';
var urlsToCache = [
'/clientsTemplate'
];
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/offline-worker.js');
}
self.addEventListener('install', function(evt) {
evt.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
)
});
然后你可以按如下方式实现抓取:
self.addEventListener('fetch', function (event) {
event.respondWith(
fetch(event.request).then(function (response) {
//the url concatenate is a bit hacky, works only if you don't have any url params
return response || caches.match(event.request.url+"Template");
})
);
});
Stefs answer 显示了一个简单的解决方案,如果应用程序中的每个页面都有一个离线模式版本。到目前为止,我已经重写了获取事件的侦听器。这可能是仅缓存有限数量的离线模式页面的最简单方法。现在,只有一个这样的页面,/clients
。一些其他页面和资产的 'standard' 版本也被缓存。
var CACHE_NAME = 'app-cache';
var urlsToCache = [
'/offline/clients',
'/css/bootstrap.min.css',
'js/bootstrap.min.js',
'/'
];
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/offline-worker.js');
}
// Open cache and add URLs to be cached
self.addEventListener('install', function(evt) {
evt.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll(urlsToCache);
})
)
});
// Define responses
self.addEventListener('fetch', function(event) {
var request = event.request;
event.respondWith(
// Try to get page from server
fetch(request).catch(function(error) {
// Request failed: Get page from cache
return caches.open('app-cache').then(function(cache) {
// There's an offline mode version for this page
if (request.url.indexOf('myapp.test/clients') > -1) {
return cache.match('offline/clients');
}
// Standard version is used even in offline mode
else {
return cache.match(request.url);
}
});
})
);
});
我会通过 JS 渲染动态部分(组件)。每个 JS 部分将通过 Ajax 接收它需要的数据。那么平时的HTML和JS就可以缓存起来,以后离线使用。一旦用户离线,service worker 就可以开始从 IndexedDB 而不是后端返回数据。缓存的 HTML 和 JS 也将由 service worker 提供。