【问题标题】:Request formData in Service Worker - TypeError: Failed to fetch在 Service Worker 中请求 formData - TypeError:无法获取
【发布时间】:2020-05-11 16:06:53
【问题描述】:

我使用 service worker 作为代理,它抛出 TypeError: Failed to fetch random and in a奇怪的方式。

有时,const formData = await request.formData(); 失败并抛出 TypeError: Failed to fetch。

我将文件存储在 FormData 中,await request.formData() 在大多数情况下都可以正常工作。但是,如果某个特定文件一次失败,那么下一次它将失败,仅针对该特定文件。其余文件都可以工作(除了这种罕见的情况)。

如果我知道可能出了什么问题,我将不胜感激,它是 Service Worker 错误,还是可能存在可能导致这种行为的特定条件。

async function handleUploadFileRequest(request) {
  const formData = await request.formData();
  const file = formData.get('file');

  const response = await fetch(`${endpoint}/api/v2/uploads.json?filename=${file.name}`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/binary'
    },
    body: file,
  });

  return response.clone();
}

self.addEventListener('fetch', (event) => {
  if (!token || !endpoint) {
    const params = new URL(location).searchParams;
    endpoint = params.get('endpoint');
    token = params.get('token');
  }

  const handleRequest = async () => {
    try {
      const { request } = event;

      if (request.method === 'POST') {
        const isUploadFileRequest = request.url.includes('/request_uploads');
        const isSubmitFormRequest = request.url.includes('/request');

        if (isUploadFileRequest) {
          return handleUploadFileRequest(request);
        }

        if (isSubmitFormRequest) {
          return handleSubmitRequest(request);
        }
      }

      if (request.method === 'DELETE') {
        const isDeleteFileRequest = request.url.includes('/requests/new');

        if (isDeleteFileRequest) {
          return new Response(true, { status: 200 });
        }
      }

      if (request.method === 'GET') {
        const isSuggestionsRequest = request.url.includes('/suggestions');

        if (isSuggestionsRequest) {
          const url = request.url;
          const newUrl = `${url}&jwt=${token}`;
          const newRequest = new Request(newUrl, request);
          const response = await fetch(newRequest);

          return new Response(await response.text(), {
            status: response.status,
            headers: { 'content-type': 'application/json' }
          });
        }

        const isAnswerBotRequest = request.url.includes('/answerBot.js');

        if (isAnswerBotRequest) {
          return new Response('var answerBot = { init: (locale) => {}};', { status: 200 });
        }
      }

      return fetch(request);
    } catch (error) {
      return fetch(request);
    }
  };

  event.respondWith(handleRequest());
});

【问题讨论】:

  • 您能发布您的整个fetch 处理程序吗?那 sn-p 一定不是一切;如果是,那么您将使用Responseundefined 来响应所有上传的网络请求。
  • 感谢您的回复,我已经更新了一个 fetch 处理程序 sn-p,但我很确定我只处理 handleUploadFileRequest 中的上传请求,其余请求按预期处理跨度>

标签: javascript service-worker


【解决方案1】:

"consume" the body 对象只能Request 一次。

handleUploadFileRequest() 内部,当您调用request.formData() 时,您最终会消耗身体。如果handleUploadFileRequest() 因任何原因最终抛出异常,您的

catch (error) {
  return fetch(request);
}

block 被触发,此时你最终会尝试第二次消耗request 的主体。那总是会失败的。

我建议进行两项更改:

  1. 在使用其主体之前克隆 request 对象:
function handleUploadFileRequest(request) {
  const clonedRequest = request.clone();
  const formData = await clonedRequest.formData();
  // ...
}

通过这样做,您将保持原始Request 对象的主体不受干扰。如果您希望 catch() 块中的 fetch(request) 工作,您需要调用 clone() 以获取可能最终消耗 request 主体的任何代码路径。

  1. 在您的catch() 处理程序中添加一些日志记录,以找出引发异常的原因:
catch (error) {
  console.log('Falling back to network due to: ', error);
  return fetch(request);
}

我不确定是什么当前导致您的失败,但希望一些额外的日志记录可以帮助您发现问题所在,clone() 应该让您的回退真正成功。

【讨论】:

    猜你喜欢
    • 2018-03-06
    • 2018-07-27
    • 1970-01-01
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 2018-06-09
    • 1970-01-01
    相关资源
    最近更新 更多