8

我不断收到此错误:

未捕获(承诺中)DOMException:无法在“FetchEvent”上执行“respondWith”:该事件已得到响应。

我知道如果 fetch 函数中发生异步操作,服务人员会自动响应,但我无法确定这段代码中的哪一位是违规者:

importScripts('cache-polyfill.js');

self.addEventListener('fetch', function(event) {

  var location = self.location;

  console.log("loc", location)

  self.clients.matchAll({includeUncontrolled: true}).then(clients => {
    for (const client of clients) {
      const clientUrl = new URL(client.url);
      console.log("SO", clientUrl);
      if(clientUrl.searchParams.get("url") != undefined && clientUrl.searchParams.get("url") != '') {
        location = client.url;
      }
    }

  console.log("loc2", location)

  var url = new URL(location).searchParams.get('url').toString();

  console.log(event.request.hostname);
  var toRequest = event.request.url;
  console.log("Req:", toRequest);

  var parser2 = new URL(location);
  var parser3 = new URL(url);

  var parser = new URL(toRequest);

  console.log("if",parser.host,parser2.host,parser.host === parser2.host);
  if(parser.host === parser2.host) {
    toRequest = toRequest.replace('https://booligoosh.github.io',parser3.protocol + '//' +  parser3.host);
    console.log("ifdone",toRequest);
  }

  console.log("toRequest:",toRequest);

  event.respondWith(httpGet('https://cors-anywhere.herokuapp.com/' + toRequest));
  });
});

function httpGet(theUrl) {
    /*var xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
    xmlHttp.send( null );
    return xmlHttp.responseText;*/
    return(fetch(theUrl));
}

任何帮助,将不胜感激。

4

2 回答 2

17

问题是您的调用event.respondWith()是在您的顶级承诺的.then()子句中,这意味着它将在顶级承诺解决后异步执行。为了获得您期望的行为,event.respondWith()需要作为fetch事件处理程序执行的一部分同步执行。

你的承诺中的逻辑有点难以遵循,所以我不确定你想要完成什么,但总的来说你可以遵循这个模式:

self.addEventListerner('fetch', event => {
  // Perform any synchronous checks to see whether you want to respond.
  // E.g., check the value of event.request.url.
  if (event.request.url.includes('something')) {
    const promiseChain = doSomethingAsync()
      .then(() => doSomethingAsyncThatReturnsAURL())
      .then(someUrl => fetch(someUrl));
      // Instead of fetch(), you could have called caches.match(),
      // or anything else that returns a promise for a Response.

    // Synchronously call event.respondWith(), passing in the
    // async promise chain.
    event.respondWith(promiseChain);
  }
});

这是一般的想法。(如果你最终用async/替换了 Promise,代码看起来会更干净await。)

于 2017-10-19T22:28:05.110 回答
8

在尝试在 fetch 处理程序中使用 async/await 时,我也偶然发现了这个错误。正如 Jeff 在他的回答中提到的,event.respondWith必须同步调用,并且参数可以是任何返回解析为响应的承诺的东西。由于异步函数确实返回了一个 Promise,因此您所要做的就是将 fetch 逻辑包装在一个异步函数中,该函数有时会返回一个响应对象并event.respondWith使用该处理程序进行调用。

async function handleRequest(request) {
  const response = await fetch(request)

  // ...perform additional logic

  return response
}

self.addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request));
});
于 2018-09-30T15:10:38.747 回答