Javascript Service worker/Safari/fetch事件在消息事件之前激发

Javascript Service worker/Safari/fetch事件在消息事件之前激发,javascript,jquery,service-worker,Javascript,Jquery,Service Worker,我是服务工作者的新手,我有以下情况: 下面是我的script.js中的一个块: if ('serviceWorker' in navigator) { if (navigator.serviceWorker.controller) { var msg = { 'form_data': params } navigator.serviceWork

我是服务工作者的新手,我有以下情况:

下面是我的script.js中的一个块:

if ('serviceWorker' in navigator) {
        if (navigator.serviceWorker.controller) {
                var msg = {
                    'form_data': params
                }

                navigator.serviceWorker.controller.postMessage(msg);
        }
}

$.post(url, params, function (data) {        
}).done(function(data) {
        console.log('succ');
}).fail(function() {
        console.log('fail');
});
下面是我的service-worker.js中的一块:

self.addEventListener('fetch', e => {
    const reqClone = e.request.clone();

    if (reqClone.method === 'POST') {
        e.respondWith(fetch(reqClone).catch(function(error) {
            savePostRequests(reqClone.url, form_data)
            //Function to add requests to IndexedDB
        }))
    }
});

self.addEventListener('message', function (e) {
    if (e.data.hasOwnProperty('form_data')) {
            form_data = e.data.form_data;
    }
});
而在Chrome中,消息事件在fetch事件之前触发,这意味着我在fetch中获取form_数据,而在Safari中,消息事件在fetch事件之后触发,因此我没有获取form_数据

脱机时,我需要fetch事件中的POST-call参数将它们存储在IndexedDB中

我做错了什么?有没有不同的处理方法


任何帮助都将不胜感激

您可以在service worker中拦截post请求,如果失败,则将其存储到缓存中。下面的代码应该会给你一些如何做的灵感

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

  if (event.request.clone().method === 'POST') {
    event.respondWith(fetch(event.request.clone(), {method:'POST'})
         .catch(function(error) { // cache only if it fails(offline)

           let url = event.request.clone().url;
           // adjust the response to your needs
           let fakeResponse = new Response(JSON.stringify({status: 'success', success:true})); 

           saveRequest(url, form_data); // custom function to save the request to cache

           return fakeResponse.clone();
         })

  } else {
     // handle GET requests here  
  }
为了获取form_数据,我使用了以下代码:

// service worker
// global variable
var form_data;
self.addEventListener('message', (event) => {
    if (event.data.hasOwnProperty('form_data')) {
        form_data = event.data.form_data;
    }
});
我必须在我想要缓存的每个post请求中添加消息

// plain javascript
// in ajax

// normal form data used when user is online
var data = new FormData();
data.append('photo', image);
data.append('description', description);

// adjusting form data for service worker message
var object = {};
data.forEach((value, key) => {object[key] = value});
var json = JSON.stringify(object);
var msg = {
    form_data: object,
}

// send form data to Service worker through post messages, works offline
swRegistration.active.postMessage(msg);

// submit the request normally.... (online only)
$.ajax({
        url: ajax_url,
        ...

这个解决方案远非优雅,但它对我有效

我已经在
Chrome
Safari
中测试了这个示例,但我并不依赖
postMessage
方法来发送
表单数据
参数。相反,我依赖于
ServiceWorker
侦听
fetch
事件并获取处理程序内部的请求参数的能力

self.addEventListener(`fetch`,event=>{
const requestClone=event.request.clone()
事件响应(
(异步函数(){
const params=await requestClone.text().catch(err=>err)
if(参数instanceof Error){
//这是一个简单的检查,但要适当地处理错误
}
if(event.request.method==`POST`){
log(`POST request with params:${params}`)
//你在这里工作吗
}
返回获取(event.request)
})()
)
})
请注意,您必须为
事件.request
创建一个
克隆
,以便能够对其调用
text()
方法,因为“请求是一个流,只能使用一次”,因此如果您试图获取请求的
参数
,然后将其用于其他用途,则会遇到问题

此外,您可以使用以下任何方法从请求中检索正文,因此请使用适当的方法:

  • event.request.arrayBuffer()
  • event.request.blob()
  • event.request.json()
  • event.request.text()
  • event.request.formData()
无论如何,假设上述代码片段包含在您的
ServiceWorker
文件中,以下示例在两种浏览器中的行为相同:

fetch(“https://jsonplaceholder.typicode.com/posts", {
方法:“张贴”,
body:JSON.stringify({title:“foo”,body:“bar”,userId:1}),
标题:{“内容类型”:`application/json`}
})
.then(response=>response.json())
.then(json=>console.log(`fetchresponse`,json))
.catch(error=>console.error(`fetcherror`,error));
//控制台日志
//>>用{“title”:“foo”,“body”:“bar”,“userId”:1}(worker.js)发布请求
//>>获取响应{title:“foo”,body:“bar”,userId:1,id:101}(index.js)

希望这能有所帮助。

我对您的代码有点困惑-您是否试图在完成提取后向服务人员发送消息?您的代码中
参数在哪里?它是如何填充的?@goto1我的最终目标是将失败的POST请求(脱机)及其参数添加到IndexedDB中。params被填充(这只是我代码中的一块),我不想在我的问题中添加不相关的内容(如果你真的认为有必要,我可以添加)。那么为什么不通过
SW
检查所有
POST
请求,捕捉错误,抓取请求的
主体,这将是你的params,然后使用它将其保存在
IndexedDB
?@goto1如何获取请求的正文?这是我最初的问题。我有一个例子,当触发
获取
请求时,会在
ServiceWorker
中获取
POST
请求的
参数。它们在
Chrome
Safari
中的工作方式相同-这就是你想要的吗?它看起来与我的代码没有太大的不同。你试过在Safari上运行它吗?