admin 管理员组

文章数量: 1086019

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.

本文标签: javascriptHow can I stream a video from a ServiceWorkerStack Overflow