mil*_*nio 4 mobile-safari service-worker progressive-web-apps
我正在努力用一个小视频为iOS PWA创建一个简单的POC.
https://test-service-worker.azurewebsites.net/
我有简单的服务工作者注册,我缓存一个小的(700kB)视频.当我在线时页面工作得很好.当我打开飞行模式并离线时,页面仍然重新加载但视频无法播放.
此POC基于Google Chrome示例 https://googlechrome.github.io/samples/service-worker/prefetch-video/ 此示例中的视频无法在iOS中脱机运行,因为它只能缓存50MB.我的只有700kB,远低于极限.
我的POC在Chrome中运行得很好但在最新的移动Safari(iOS 11.4)中却不行.
为了在iOS 11.4+上运行,我需要更改什么?这是Safari中的错误吗?
事实证明,Safari非常严格.我在这里留下这个问题 - 希望它能节省一些人的时间.
发生了什么:
Safari只请求部分视频 - 首先它会请求'range:bytes = 0-1'响应.它期望HTTP 206响应,这将显示文件的大小
根据响应,它学习视频的长度,然后询问文件的各个字节范围(例如范围:字节= 0-20000等)
如果您的响应时间超过请求,Safari将立即停止处理后续请求.
这正是Google Chrome示例中发生的事情以及我的POC中发生的事情.因此,如果您使用这样的提取,它将在线和离线工作:
//This code is based on https://googlechrome.github.io/samples/service-worker/prefetch-video/
self.addEventListener('fetch', function(event) {
headersLog = [];
for (var pair of event.request.headers.entries()) {
console.log(pair[0]+ ': '+ pair[1]);
headersLog.push(pair[0]+ ': '+ pair[1])
}
console.log('Handling fetch event for', event.request.url, JSON.stringify(headersLog));
if (event.request.headers.get('range')) {
console.log('Range request for', event.request.url);
var rangeHeader=event.request.headers.get('range');
var rangeMatch =rangeHeader.match(/^bytes\=(\d+)\-(\d+)?/)
var pos =Number(rangeMatch[1]);
var pos2=rangeMatch[2];
if (pos2) { pos2=Number(pos2); }
console.log('Range request for '+ event.request.url,'Range: '+rangeHeader, "Parsed as: "+pos+"-"+pos2);
event.respondWith(
caches.open(CURRENT_CACHES.prefetch)
.then(function(cache) {
return cache.match(event.request.url);
}).then(function(res) {
if (!res) {
console.log("Not found in cache - doing fetch")
return fetch(event.request)
.then(res => {
console.log("Fetch done - returning response ",res)
return res.arrayBuffer();
});
}
console.log("FOUND in cache - doing fetch")
return res.arrayBuffer();
}).then(function(ab) {
console.log("Response procssing")
let responseHeaders= {
status: 206,
statusText: 'Partial Content',
headers: [
['Content-Type', 'video/mp4'],
['Content-Range', 'bytes ' + pos + '-' +
(pos2||(ab.byteLength - 1)) + '/' + ab.byteLength]]
};
console.log("Response: ",JSON.stringify(responseHeaders))
var abSliced={};
if (pos2>0){
abSliced=ab.slice(pos,pos2+1);
}else{
abSliced=ab.slice(pos);
}
console.log("Response length: ",abSliced.byteLength)
return new Response(
abSliced,responseHeaders
);
}));
} else {
console.log('Non-range request for', event.request.url);
event.respondWith(
// caches.match() will look for a cache entry in all of the caches available to the service worker.
// It's an alternative to first opening a specific named cache and then matching on that.
caches.match(event.request).then(function(response) {
if (response) {
console.log('Found response in cache:', response);
return response;
}
console.log('No response found in cache. About to fetch from network...');
// event.request will always have the proper mode set ('cors, 'no-cors', etc.) so we don't
// have to hardcode 'no-cors' like we do when fetch()ing in the install handler.
return fetch(event.request).then(function(response) {
console.log('Response from network is:', response);
return response;
}).catch(function(error) {
// This catch() will handle exceptions thrown from the fetch() operation.
// Note that a HTTP error response (e.g. 404) will NOT trigger an exception.
// It will return a normal response object that has the appropriate error code set.
console.error('Fetching failed:', error);
throw error;
});
})
);
}
});Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1595 次 |
| 最近记录: |