在服务工作者中,我可以定义下面提到的服务工作者入门期间缓存的资源数组:
public interface SendMediaApiInterface {
@Multipart
@POST("url")
void sendImage(@Part("here_is_the_attribute_name_in_webservice") TypedFile attachments, Callback<YourObject> response);}
如何在服务工作者中定义路径/目录,以便服务工作者不是编写所有文件名,而是从给定路径/目录中选择所有文件并将所有文件添加到缓存中?
答案 0 :(得分:3)
这是不可能的。 SW(或浏览器,就此而言)对Web服务器上特定路径中的文件没有任何线索。您必须提供要缓存的文件的名称。有关同一问题的更多信息here.
您是否使用某些构建工具自动生成文件列表?如果没有,你很可能应该:)
编辑:
SW工具最常用的库之一是Workbox。它们提供runtime-caching和precaching资产。他们还为例如构建工具插件。 Webpack和Gulp。
运行时缓存的工作原理是,如果资产存在于缓存中,则从缓存中提供资产,无论如何都要从服务器更新资产。基本上,每个新资产最初都将从网络请求,然后在后续请求中从缓存中返回。
EDIT2:
是的,您可以在某种程度上使用不带NPM的Workbox。您需要运行NPM脚本等来收集要缓存的文件的文件名。但是,您仍然可以通过在手写的SW文件中导入Workbox.js脚本来实现运行时缓存。
只是说
importScript("https://unpkg.com/workbox-sw@2.1.0/build/importScripts/workbox-sw.prod.v2.1.0.js")
在SW的顶部导入最新的(截至目前)Workbox版本。您可以看到runtime-caching example here too中发生的情况。
您也可以下载上面的.js文件并将其放在您自己的服务器上,然后从相对路径导入。
答案 1 :(得分:2)
是的。要从多个目录缓存许多文件...
我在服务工作者中使用辅助功能
我将其命名为“ getFileArray(...)”。
它采用目录名称的一个字符串参数。
对于多个目录,我在其中使用了一个数组
Promise.all:
let cache_name = "cache-A";
let filesToCache = [
"https://myApp.com/",
"index.php?launcher=true;homescreen=1",
"manifest.json",
"favicon.ico",
];
self.addEventListener( "install", eo => {
self.skipWaiting();
eo.waitUntil( filesAreCached() );
} );
///////| helper functions |/////////
function filesAreCached(){
Promise.all([
/* name the directories whose files you wish to cache */
getFileArray( "js" ),
getFileArray( "css" ),
getFileArray( "images" ),
getFileArray( "screens" ),
getFileArray( "modals" )
])
.then( promiseArray => {
let promisedFiles = [];
promiseArray.forEach( array => {
promisedFiles = promisedFiles.concat( array ) ;
} );
return promisedFiles;
})
.then( promisedFiles => {
filesToCache = filesToCache.concat( promisedFiles );
console.log( "Cached files:", filesToCache );
return self.caches.open( cache_name );
})
.then( cache => cache.addAll( filesToCache ) );
}
/*
the following function calls a server script that returns an array of filenames,
each one prepended with the directory name:
*/
async function getFileArray( directory ){
let form = new FormData();
form.append( `directory`, directory );
let fileArray = await fetch( `php/getFileArray.php`, { method: `POST`, body: form })
.then( response => response.json() ) ;
return fileArray;
}
PHP代码(getFileArray.php)如下:
<?php
/*
Motivation: To help provide an accurate list of files
for JavScript service workers to cache. Saves time,
tedium, and possible typos in doing it manually.
Use the POSTed directory path to return an array
that lists all the files in that directory,
less the "." and ".." entries.
Prepend the directory name to the filenames so that
we have the "full path" to each file.
Return this array as a json string.
*/
$directory = $_POST["directory"] ;
/*
You should probably sanitize $directory of all "../" prefixes
in order to prevent a Directory Traversal Attack.
Using str_replace("/", "", $directory) has been suggested.
It throws an error but prevents the attack.
*/
$filelistArray = scandir( "../" . $directory );
$cleanFileArray = array();
foreach( $filelistArray as $file ){
if ( $file !== "." and $file !== ".." ){
array_push( $cleanFileArray, $directory . "/" . $file );
}
}
$fileArrayJson = json_encode( $cleanFileArray );
exit( $fileArrayJson );
?>
当然,可以使用任何后端语言。
这项技术可能有点简单,
但这对我有用:)
答案 2 :(得分:1)
使用Workbox sw。
运行时缓存<强>服务worker.js:强>
importScripts('https://unpkg.com/workbox-sw@0.0.2/build/importScripts/workbox-sw.dev.v0.0.2.js');
importScripts('https://unpkg.com/workbox-runtime-caching@1.3.0/build/importScripts/workbox-runtime-caching.prod.v1.3.0.js');
importScripts('https://unpkg.com/workbox-routing@1.3.0/build/importScripts/workbox-routing.prod.v1.3.0.js');
const assetRoute = new workbox.routing.RegExpRoute({
regExp: new RegExp('^http://localhost:8081/jobs/static/*'),
handler: new workbox.runtimeCaching.CacheFirst()
});
const router = new workbox.routing.Router();
//router.addFetchListener();
router.registerRoutes({routes: [assetRoute]});
router.setDefaultHandler({
handler: new workbox.runtimeCaching.CacheFirst()
});
在我的html文件中加载Servcie worker的脚本。
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('http://localhost:8081/jobs/static/service-worker.js?v=4').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
</script>
答案 3 :(得分:0)
可以。我也遇到了此类问题,并且使用 performance
找到了不错的解决方案。这是我的sw.js
:
const KEY = 'key';
self.addEventListener('install', (event) => {
event.waitUntil(self.skipWaiting());
});
self.addEventListener('message', (event) => {
if (event.data.type === 'CACHE_URLS') {
event.waitUntil(
caches.open(KEY)
.then( (cache) => {
return cache.addAll(event.data.payload);
})
);
}
});
这是我的main.js
:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js', { scope: '/' })
.then((registration) => {
const data = {
type: 'CACHE_URLS',
payload: [
location.href,
...performance.getEntriesByType('resource').map((r) => r.name)
]
};
registration.installing.postMessage(data);
})
.catch((err) => console.log('SW registration FAIL:', err));
}
这样,您还可以添加一些过滤器,该过滤器将缓存特定的路径。