Service Worker 是不是会不断地从服务器请求、响应?

Posted

技术标签:

【中文标题】Service Worker 是不是会不断地从服务器请求、响应?【英文标题】:does service worker request, response from server continuously?Service Worker 是否会不断地从服务器请求、响应? 【发布时间】:2016-01-27 07:05:08 【问题描述】:

我正在使用服务器发送事件来显示通知。我创建了一个服务工作者,并在我运行项目后使用 EventSource 与服务器连接(在我的情况下我使用了一个 servlet。)。一切正常。

但是事件里面的内容是计数执行的。我想知道为什么? 我的另一个问题是

一旦我关闭标签。它停止发送通知。服务人员正在运行,服务器也在运行。但为什么会停止?

这是我的服务工作者代码。

var eventSource = new EventSource("HelloServ");
//MyDiv1 is a custom event
eventSource.addEventListener("MyDiv1",function(event)
    console.log("data from down" , event.data);

    var title = event.data;
    //below notification is displaying continuously. why ?
var notification = new Notification(title, 
icon: 'http://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png',
body: event.data,
);
notification.onclick = function () 
window.open("http://ageofthecustomer.com/wp-content/uploads/2014/03/success.jpg");      
        ;
    console.log("down");
); 

这是我的 servlet 代码;

response.setContentType("text/event-stream");   
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        String upVote = "my up vote";
            writer.write("id:1\n");
            writer.write("event:myid\n");
            writer.write("data: "+ upVote +"\n");
            writer.write("data: "+"new data 2\n\n");
            System.out.println("servlet "+ i);
            writer.flush();
            i++;
writer.close();

【问题讨论】:

这不是您应该实现推送通知的方式。 Service Worker 并不总是在运行,它的生命周期很短。我建议你看看这里的演示:serviceworke.rs/push-simple.html 无法访问该网址。你能再检查一下吗? serviceworke.rs/push-simple.html URL 正确。 【参考方案1】:

Service Worker 的生命周期有限,您不应使用 Web 套接字或服务器发送事件之类的东西。 推送通知以不同的方式实现。

在您的页面中,您需要为用户订阅推送通知。订阅是一个端点 URL(和一组密钥,如果您计划使用有效负载)。用户订阅后,您需要将订阅信息发送到您的服务器。

服务器将通过对端点 URL 的 POST 请求向用户发送推送通知。

当推送通知到达时,Service Worker 将被唤醒,其 'push' 事件处理程序将被执行。

一个简单的例子(更复杂的例子,看看ServiceWorker Cookbook)。

页面

// Register a Service Worker.
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) 
  // Use the PushManager to get the user's subscription to the push service.
  return registration.pushManager.getSubscription()
  .then(function(subscription) 
    // If a subscription was found, return it.
    if (subscription) 
      return subscription;
    

    // Otherwise, subscribe the user (userVisibleOnly allows to
    // specify that you don't plan to send notifications that
    // don't have a visible effect for the user).
    return registration.pushManager.subscribe(
      userVisibleOnly: true
    );
  );
).then(function(subscription) 
  // subscription.endpoint is the endpoint URL that you want to
  // send to the server (e.g. via the Fetch API or via
  // XMLHTTPRequest).
  console.log(subscription.endpoint);

  // Here's an example with the Fetch API:
  fetch('./register', 
    method: 'post',
    headers: 
      'Content-type': 'application/json'
    ,
    body: JSON.stringify(
      endpoint: subscription.endpoint,
    ),
  );
);

服务工作者

// Register event listener for the 'push' event.
self.addEventListener('push', function(event) 
  // Keep the service worker alive until the notification is created.
  event.waitUntil(
    self.registration.showNotification('Title', 
      body: 'Body',
    )
  );
);

服务器

在服务器中,只需向端点 URL 发送一个 POST 请求。 例如,使用 curl:

curl -X POST [endpointURL]

或者,如果您使用的是 Node.js,则可以使用 web-push 库 (https://github.com/marco-c/web-push):

var webPush = require('web-push');
webPush.sendNotification(req.query.endpoint, req.query.ttl);

在 Java 中,您可以使用此类 (https://github.com/marco-c/java-web-push),它隐藏了实现的细节以及当前版本 Firefox 和 Chrome 中的协议之间的差异(由于 Chrome 将使用 Web,差异注定会消失尽快推送协议)。 这是一个“手动”示例,其中包含实现 Web 推送协议的推送服务(目前仅适用于 Firefox):

URL url = new URL(endpointURL);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");

OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());

writer.write("");
writer.flush();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
while ((line = reader.readLine()) != null) 
  System.out.println(line);

writer.close();
reader.close();

【讨论】:

感谢您的回复。我正在使用java servlet。那么,我应该如何使用 java 而不是 curl 或 node js 编写服务器端? 我在回复中添加了一个示例。虽然它与 Web 推送并不严格相关,但它是一个简单的 POST 请求,就像任何其他请求一样(您会在网上找到很多关于如何使用 Java 发送 POST 请求的示例和文档)。 谢谢。但现在我在控制台中遇到了这个错误。我认为发件人的身份应该在清单中提及。错误 - “未捕获(承诺中)DOMException:注册失败 - 未提供发件人 ID”所以发件人的 ID 是什么? 非常感谢您的回复。但我想知道有没有办法在不使用 GCM 的情况下实现这一点。我想使用我自己的服务器。而不是使用 GCM。这可能吗? 不行,你必须使用浏览器提供的推送服务。在 Firefox 中,您可以从 about:config 修改 dom.push.serverURL 配置值以使用不同的服务器,但您不能通过 javascript 自动更改它(在 Chrome 中可能有类似的方式来使用自定义服务器,我不知道)不知道)。

以上是关于Service Worker 是不是会不断地从服务器请求、响应?的主要内容,如果未能解决你的问题,请参考以下文章

如何在上层文件夹中添加“Service-Worker-Allowed”来注册服务工作者范围

使用.NET 6.0创建Worker Service服务程序,并注册Windows服务程序

web worker 与 service worker

Service worker 简介

Service worker 简介

Rails 对 service-worker.js 的未知调用