最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I stream a video from a ServiceWorker? - Stack Overflow

programmeradmin0浏览0评论

I have a service worker that catches my page's requests (fetch event), and when the URL matches a certain pattern, it would fetch another URL and replace the response with that new content. It works perfectly for text data (JS, XML...) or binary data (e.g. images), but when it es to video, there is a glitch.

I am using Chrome 41 on OSX.

This is the simplified code of my worker:

self.addEventListener('fetch', function(event) {
  var url = event.request.url;
  console.log('SW: fetch', url);
  if (/\.mp4$/.test(url)) {
    url = '.mp4';
    var options = {
      credentials: 'include',
      mode: 'no-cors'
    };
    event.respondWith(fetch(url, options));
  }
});

And this is the simplified code in my HTML page:

navigator.serviceWorker.register('sw.js').then(function(reg) {
  console.info('ServiceWorker registration successful for', reg.scope);

  var video = document.createElement('video');
  video.src = '/video.mp4';
  video.controls = true;
  video.autoplay = true;
  video.onerror = function(err) {
    console.error('Video load fail', err);
  }
  video.onload = function(data) {
    console.info('Video load success');
  }
  document.body.appendChild(video);

}).catch(function(err) {
  console.error('ServiceWorker registration failed:', err);
});

The first time you load the page, the worker installs, so the video request is not caught, thus failing. But when you reload the page (without cleaning the cache), it is successfully caught, and the worker successfully loads the video (HTTP 200 in its inspector), but for some reason, the main page throws a net::ERR_FAILED.

And I cannot manually read/stream it, because it es from a different origin, resulting in an "opaque" Response type:

UPDATE: updating to Chrome 42, the error is now HTTP 400 Service Worker Fallback Required (from ServiceWorker). Strange thing is that the source code (line 510) indicates that it should only be raised when CORS headers are missing, but here the mode is no-cors.

I have a service worker that catches my page's requests (fetch event), and when the URL matches a certain pattern, it would fetch another URL and replace the response with that new content. It works perfectly for text data (JS, XML...) or binary data (e.g. images), but when it es to video, there is a glitch.

I am using Chrome 41 on OSX.

This is the simplified code of my worker:

self.addEventListener('fetch', function(event) {
  var url = event.request.url;
  console.log('SW: fetch', url);
  if (/\.mp4$/.test(url)) {
    url = 'https://vjs.zencdn/v/oceans.mp4';
    var options = {
      credentials: 'include',
      mode: 'no-cors'
    };
    event.respondWith(fetch(url, options));
  }
});

And this is the simplified code in my HTML page:

navigator.serviceWorker.register('sw.js').then(function(reg) {
  console.info('ServiceWorker registration successful for', reg.scope);

  var video = document.createElement('video');
  video.src = '/video.mp4';
  video.controls = true;
  video.autoplay = true;
  video.onerror = function(err) {
    console.error('Video load fail', err);
  }
  video.onload = function(data) {
    console.info('Video load success');
  }
  document.body.appendChild(video);

}).catch(function(err) {
  console.error('ServiceWorker registration failed:', err);
});

The first time you load the page, the worker installs, so the video request is not caught, thus failing. But when you reload the page (without cleaning the cache), it is successfully caught, and the worker successfully loads the video (HTTP 200 in its inspector), but for some reason, the main page throws a net::ERR_FAILED.

And I cannot manually read/stream it, because it es from a different origin, resulting in an "opaque" Response type: http://www.w3/TR/service-workers/#cross-origin-resources

UPDATE: updating to Chrome 42, the error is now HTTP 400 Service Worker Fallback Required (from ServiceWorker). Strange thing is that the source code (line 510) indicates that it should only be raised when CORS headers are missing, but here the mode is no-cors.

Share Improve this question edited Apr 16, 2015 at 13:59 Antoine asked Apr 16, 2015 at 10:18 AntoineAntoine 5,6996 gold badges35 silver badges55 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 7

First off, I'd remend trying in the current Chrome Canary, which currently corresponds to release 44.0.2371.0. The developer tooling around service workers continues to improve with each new Chrome release, and it's gotten much better with version 43+ in general.

It doesn't look like opaque Response objects can be used for the src of a <video> element, and I'm assuming that's deliberate. (Opaque Responses can be used for certain purposes, and I'm afraid I don't have a plete rundown of what will and won't work with an opaque Response.)

But in any case, you're fortunate in that vjs.zencdn supports CORS, so you can get away with using the default, CORS-enabled Request, which will give you a non-opaque Response.

One thing that you can't do is use credentials: 'include' in your CORS Request, because it will lead to a Fetch API cannot load https://vjs.zencdn/v/oceans.mp4. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. error. This doesn't seem like it's an issue with your particular host, since credentials aren't required.

When I switched your code to use event.respondWith(fetch('https://vjs.zencdn/v/oceans.mp4')); everything worked fine.

发布评论

评论列表(0)

  1. 暂无评论