我在tomcat 8.0上使用java尝试了SSE(Server-Sent-Events).以下是我注意到的一些事情.
我单击一个自动向servlet发出请求的按钮.执行Servlet的GET方法,返回事件流.收到完整的流后,页面会再次自动发出另一个请求,再次接收相同的数据!我没有无限循环!!!
服务器上实际发生了什么?在正常情况下,tomcat会创建一个线程来处理每个请求.现在发生了什么?
确保事件流只发送一次到同一个连接/浏览器会话的正确方法是什么?
确保事件流关闭且服务器上不会产生资源开销的正确方法是什么?
如何区分GET和POST请求.为什么选择GET?
在Tomcat上使用SSE为时尚早?任何性能问题?
这是好奇的代码,
@WebServlet("/TestServlet")
public class TestServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//content type must be set to text/event-stream
response.setContentType("text/event-stream");
//cache must be set to no-cache
response.setHeader("Cache-Control", "no-cache");
//encoding is set to UTF-8
response.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
for(int i=0; i<10; i++) {
System.out.println(i);
writer.write("data: "+ i +"\n\n");
writer.flush();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
writer.close();
}
}
Run Code Online (Sandbox Code Playgroud)
页面上的Javascript(页面上没有其他内容),
<button onclick="start()">Start</button> …Run Code Online (Sandbox Code Playgroud) 有没有办法在Chrome(或Firefox)中查看/调试Server-Sent Events?我希望他们出现在Chrome开发者工具的网络标签中.我所知道的最接近的方式是下载到Wireshark,但相比之下这相当麻烦.
例如,请访问http://www.emojitracker.com/.您将看到使用服务器中的数据实时更新页面,但网络选项卡中不显示任何活动.(它在/application.js的第97行订阅服务器事件.)
Microsoft Edge是否支持HTML5 SSE(服务器端事件)?
我想它们符合我的要求完美,看起来他们应该是简单的实现获得与服务器端事件交手,但我不能让过去一个模糊的错误,什么样子反复被关闭了连接并重新-opened.我尝试的一切都基于这个和其他教程.
PHP是一个单独的脚本:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
function sendMsg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));
?>
Run Code Online (Sandbox Code Playgroud)
并且JavaScript看起来像这样(在身体负载上运行):
function init() {
var source;
if (!!window.EventSource) {
source = new EventSource('events.php');
source.addEventListener('message', function(e) {
document.getElementById('output').innerHTML += e.data + '<br />';
}, false);
source.addEventListener('open', function(e) {
document.getElementById('output').innerHTML += 'connection opened<br />';
}, false);
source.addEventListener('error', function(e) {
document.getElementById('output').innerHTML += 'error<br />'; …Run Code Online (Sandbox Code Playgroud) Server Sent Events似乎是jQuery插件的主要候选者."权威指南"第921页显示了如何使用EventSource.但是后来第923页说IE使用attachEvent而不是addEventListener.
我在github上找到了jQuery.EventSource,但是没有提到attachEvent.它反过来使用$ .ajax.
问:如果我要使用JavaScript的EventSource功能,我应该使用jQuery.EventSource吗?
我必须有更多的jQuery!
也许这是Flask的一个问题,没有办法在服务器端处理断开连接事件.
在Response类中,有一个名为"call_on_close"的方法,我们可以在其中添加一个没有参数的函数,例如on_close(),它会在响应对象的close方法被调用时触发,但是当我调用EventSource时这不会发生.在Javascript中从客户端关闭().
服务器端的代码:
from flask import Response
r = Response(stream(), ...)
r.call_on_close(on_close)
return r
def on_close():
print "response is closed!"
def stream():
... # subscribe to redis
for message in pubsub.listen():
....
yield 'data: %s\n\n' % message
Run Code Online (Sandbox Code Playgroud)
在客户端:使用SSE向页面添加卸载处理程序
$(window).unload(
function() {
sse.close();
}
}
Run Code Online (Sandbox Code Playgroud)
什么都错了?
任何建议或解决方案与代码表示赞赏!
提前致谢!
我有一个带有以下控制器的AngularJS应用程序.它可以在常规JSON资源和手动更新请求上使用GET,但我无法使用Server-Sent Events.我面临的问题是,在收到SSE事件并设置/更新openListingsReport变量后,我的视图没有得到更新.我显然错过了一个非常基本的概念.请帮我解决这个问题.
var rpCtrl = angular.module('rpCtrl', ['rpSvc']);
rpCtrl.controller('rpOpenListingsCtrl', ['$scope', 'rpOpenListingsSvc',
function ($scope, rpOpenListingsSvc) {
$scope.updating = false;
if (typeof(EventSource) !== "undefined") {
// Yes! Server-sent events support!
var source = new EventSource('/listings/events');
source.onmessage = function (event) {
$scope.openListingsReport = event.data;
$scope.$apply();
console.log($scope.openListingsReport);
};
}
} else {
// Sorry! No server-sent events support..
alert('SSE not supported by browser.');
}
$scope.update = function () {
$scope.updateTime = Date.now();
$scope.updating = true;
rpOpenListingsSvc.update();
}
$scope.reset = function () {
$scope.updating = false; …Run Code Online (Sandbox Code Playgroud) 我实现了一些代码来查询数据库中的任何更改并发送事件. 这是我的PHP脚本的代码
header("Content-Type: text/event-stream");
header('Cache-Control: no-cache');
//****Some code here to query the database
echo "event: message\n";
echo "data: change_from_database \n";
echo "\n\n";
ob_flush();
flush();
Run Code Online (Sandbox Code Playgroud)
我依靠浏览器每次连接关闭时自动重新连接,所以我没有在我的服务器代码上实现任何循环.另外,我从这个线程中了解到,实现无限循环有许多缺点.
所以一切都在客户端工作正常:每次连接关闭时浏览器都会重新连接,每次服务器发送一个事件时都会触发事件; 除了没有重新连接的Firefox(40.0.2)之外.我知道它不是因为我写了一些JavaScript错误检查代码来测试这个:
var evtSource = new EventSource("../sse.php");
evtSource.onerror = function(event){
var txt;
switch( event.target.readyState ){
case EventSource.CONNECTING:
txt = 'Reconnecting...';
break;
}
console.log(txt);
}
Run Code Online (Sandbox Code Playgroud)
因此,像每一秒后,铬控制台上的控制台例如日志"Reconnecting".另一方面,Firefox重新连接一次,再也不会重新连接.
如何编写代码以使其在Firefox上运行,也许还有其他支持服务器发送事件但不自动重新连接的浏览器?
使用websocket时,我们需要一个专用的双向通信连接.如果我们使用http/2,我们有服务器维护的第二个连接.
在这种情况下,使用websocket似乎会引入不必要的开销,因为使用SSE和常规http请求,我们可以通过单个HTTP/2连接获得双向通信的优势.
你怎么看?
我有一个JMeter测试,我正在使用循环来查明某些条件是否属实.我想(并且可以)在发送服务器发送事件(SSE)的资源上使用请求,而不是轮询.它应该工作的方式是,SSE线程被启动,而另一个线程被启动,它执行最终将导致发送特定事件的请求.如果收到该事件,则应继续处理.
也许图形化更清晰.我当前的脚本看起来像这样:
ThreadGroup
|
+ request 1
+ request 2
...
+ request N
+ Transaction controller
| |
| + While controller
| + polling request
|
+ request N+1
Run Code Online (Sandbox Code Playgroud)
我想要这样的东西
ThreadGroup
|
+ request 1
+ request 2
...
+ <help needed here>
| |
| + event thread
| | + request SSE
| | + onEvent x: y = true
| + action thread
| + request N
| + While y=false wait
+ request N+1 …Run Code Online (Sandbox Code Playgroud)