PWA-缓存的视频将无法在Mobile Safari(11.4)中播放 [英] PWA - cached video will not play in Mobile Safari (11.4)

查看:124
本文介绍了PWA-缓存的视频将无法在Mobile Safari(11.4)中播放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力为iOS PWA创建一个带有小视频的简单POC.

I'm struggling to create a simple POC for iOS PWA with a small video.

https://test-service-worker.azurewebsites.net/

我注册了简单的服务人员,并且缓存了一个小的(700kB)视频.当我在线时,页面工作正常.当我打开飞行模式并脱机时,页面仍会重新加载,但视频将无法播放.

I have simple service worker registration and I cache a small (700kB) video. When I'm online the page works just fine. When I turn on airplane mode and go offline, the page is still reloaded but video will not play.

此POC基于Google Chrome示例 https://googlechrome.github.io/samples/service-worker/prefetch-视频/ 此示例中的视频肯定无法在iOS脱机版本中工作,因为它只能缓存50MB.我的只有700kB,远低于限制.

This POC is based on Google Chrome example https://googlechrome.github.io/samples/service-worker/prefetch-video/ The video from this example will not work in iOS offline for sure because it only caches 50MB. Mine is only 700kB so well below the limit.

我的POC在Chrome中运行正常,但在最新的移动Safari(iOS 11.4)中却无法运行.

My POC works just fine in Chrome but it won't in the latest mobile Safari (iOS 11.4).

要在iOS 11.4+上正常运行,我需要更改什么?这是Safari中的错误吗?

What do I need to change in order to make this work on iOS 11.4+? Is this a bug in Safari?

推荐答案

事实证明,Safari十分严格.我把问题留在这里-希望它可以节省别人的时间.

It turns out, Safari is just quite strict. I'm leaving the question here - hopefully it will save someones time.

发生了什么事

  1. Safari仅请求视频的一部分-首先,它将请求范围:字节= 0-1"响应.它期望HTTP 206响应将显示文件的大小

  1. Safari requests only part of the video - first it will request 'range: bytes=0-1' response. It expects HTTP 206 response which will reveal size of the file

根据响应,它了解视频的长度,然后询问文件的各个字节范围(例如,范围:bytes = 0-20000等)

Based on the response it learns what is the length of the video and then it asks for individual byte ranges of the file (for example range: bytes=0-20000 etc.)

如果您的回复时间超出要求,Safari会立即停止处理后续请求.

If your response is longer than requested Safari will immediately stop processing subsequent requests.

这正是Google Chrome示例中正在发生的事情以及我的POC中正在发生的事情.因此,如果您使用这样的抓取功能,则既可以在线使用又可以使用离线:

This is exactly what is happening in Google Chrome example and what was happening in my POC. So if you use fetch like this it will work both online & offline:

//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;
      });
    })
    );
  }
});

这篇关于PWA-缓存的视频将无法在Mobile Safari(11.4)中播放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆