我有一个包含Rails ActionController::Live
模块的控制器.我显示一个日志文件,正在使用读取的内容FileTail
宝石,并使用SSE
来自ActionController::Live
像这样:
class LogsController < ApplicationController
include ActionController::Live
def live
response.headers['Content-Type'] = 'text/event-stream'
sse = SSE.new(response.stream, event: 'queries')
File.open(logfile_location) do |log|
log.extend(File::Tail)
log.interval = 1
log.backward(10)
log.tail {|line| sse.write line}
end
rescue => e
Rails.logger.info "Error Message:: #{e.message}"
ensure
sse.close
end
end
Run Code Online (Sandbox Code Playgroud)
我想用它来测试live
动作Rspec
.这就是我目前拥有的:
before { get :live }
it { expect(response.headers['Content-Type']).to eq("text/event-stream") }
after {response.stream.close unless response.stream.closed? }
Run Code Online (Sandbox Code Playgroud)
如果我没有after
适当的线路,规范通过,但它只是继续监听,连接永远不会关闭,因此规格永远不会完成,你必须手动杀死它们.
如果我有这after
条线,它有时会通过,但大多数时候它会抛出异常,并且规格失败.
fatal:
No live threads left. …
Run Code Online (Sandbox Code Playgroud) 我正在开发一个股票应用程序,必须让用户浏览器更新价格变化
我不需要访问过去的数据,浏览器只需在更改时获取当前数据
是否可以过滤 dynamodb 流并公开可以与 javascript EventSource 一起使用的端点(在 api 网关后面)?
amazon-web-services server-sent-events aws-lambda eventsource
我正在尝试使用EventSource
Typescript ,但在使用命名事件时无法正确键入响应。
我试过
const evtSource = new EventSource('/my-url');
const parseMyEvent = (evt: Event) => {
const data: MyDataInterface = JSON.parse(evt.data);
console.log(data)
}
evtSource.addEventListener('my-event', parseMyEvent);
Run Code Online (Sandbox Code Playgroud)
失败,因为Event
没有属性数据
const evtSource = new EventSource('/my-url');
const parseMyEvent = (evt: MessageEvent) => {
const data: MyDataInterface = JSON.parse(evt.data);
console.log(data)
}
evtSource.addEventListener('my-event', parseMyEvent);
Run Code Online (Sandbox Code Playgroud)
失败evtSource.addEventListener('my-event', parseMyEvent)
,并显示“没有与此调用匹配的过载。”。
我知道这MessageEvent
是一个通用接口,但是我应该使用什么作为它的类型?
我正在使用 TS 3.5.3,所以我尝试安装外部类型,@types/eventsource
但也没有成功(我知道,它是用于 polyfill EventSource 库,但我尝试过)
使用通用时,evtSource.onMessage = fn
它可以正常工作,没有任何问题
应该可以在 TS 中输入 EventSource 事件的侦听器/响应,但是如何输入呢?
我目前正在为网页游戏编写通信框架,通信地图如下所示: 代码如下:
test.php的:
<!DOCTYPE html>
<html>
<head>
<title> Test </title>
<script>
function init()
{
var source = new EventSource("massrelay.php");
source.onmessage = function(event)
{
console.log("massrelay sent: " + event.data);
var p = document.createElement("p");
var t = document.createTextNode(event.data);
p.appendChild(t);
document.getElementById("rec").appendChild(p);
};
}
function test()
{
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function ()
{
if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200)
{
console.log("reciver responded: " + xhr.responseText);
}
}
xhr.open("GET", "reciver.php?d=" + document.getElementById("inp").value , true);
xhr.send();
console.log("you sent: " + document.getElementById("inp").value); …
Run Code Online (Sandbox Code Playgroud) 我正在考虑使用服务器发送的事件作为支持 api 来实现“订阅”类型。
我正在努力的是接口,更准确地说,是这种操作的 http 层。
问题:
使用本机EventSource不支持:
虽然#1 是无可辩驳的,但#2 可以使用查询参数来规避。
查询参数有大约 2000 个字符的限制(可以争论),这使得仅仅依赖它们感觉太脆弱了。
我正在考虑的解决方案是为每个可能的事件创建一个专用端点。
例如:代表各方之间已完成交易的事件的 URI:
/graphql/transaction-status/$ID
将转换为服务器中的此查询:
subscription TransactionStatusSubscription {
status(id: $ID) {
ready
}
}
Run Code Online (Sandbox Code Playgroud)
这种方法的问题是:
可能还有更多我遗漏的问题。
也许你能想到更好的方法?一个可以使用 EventSource 提供请求有效负载的更好方法吗?
我正在尝试设置一个 Spring SseEmitter 来发送正在运行的作业状态的一系列更新。它似乎有效,但是:
每当我调用emitter.complete()
Java 服务器代码时,javascriptEventSource
客户端都会调用注册的onerror
函数,然后使用新连接再次调用我的 Java 端点。这发生在 Firefox 和 Chrome 中。
我可能可以从 Java 发送一个明确的“数据结束”消息,然后检测它并eventSource.close()
在客户端上调用,但是有更好的方法吗?
emitter.complete()
在这种情况下的目的是什么?
另外,如果我总是不得不终止客户端的连接,那么我猜服务器端的每个连接都会因超时或写入错误而终止,在这种情况下,我可能想手动发回一些每隔几秒种一次?
如果我不得不做这一切,感觉就像我错过了一些东西。
TL;DR 更新:无论是从客户端关闭 EventSource 还是完全关闭客户端,php 都会继续在后端执行,并且无法报告connection_aborted()
. 为什么会这样?
我一直在 Google 和 Stack Overflow 上寻找这个问题的答案,但没有一个建议的修复可以解决这个问题:我有一个简单的页面,使用 JavaScript 和 php 测试服务器发送事件的功能。一切都运行良好,直到我意识到当客户端导航到另一个页面或刷新自身时,服务器脚本执行并没有停止。这似乎是一个常见问题,其他问题中给出的建议对我来说没有效果。
我已经调查过的 StackOverflow 问题
PHP 事件源继续执行(此处对已接受答案的评论几乎导致了某些结果,然后他们退出“在聊天中继续讨论”,并且该链接显然已损坏)
我已经调查过的链接文章和其他材料
我已经删除了我认为可能的罪魁祸首的所有代码,但问题仍然存在。我特别惊讶的是,在客户端中显式调用之后connection_aborted
继续报告,或者在 10 秒服务器循环完成之前简单地关闭客户端。这是我的确切代码,除去服务器发送的事件内容之外的所有内容后:false
EventSource.close()
sse_tests.js
document.addEventListener('DOMContentLoaded', () => {
// Set up EventSource for receiving server-sent events.
const testEventSource = new EventSource('sse_tests.php');
testEventSource.addEventListener('test', (e) => {
const data = JSON.parse(e.data);
console.log(`count: ${data.count}`);
if (data.count >= 5) {
testEventSource.close(); …
Run Code Online (Sandbox Code Playgroud) 相同的代码以前可以工作,但我不知道为什么现在不起作用。请帮忙。
我的问题是,当我使用 SSE 进行实时数据共享时。应该在 res.write( data:${JSON.stringify(dataObject)}\n\n
) 上发送的数据对象在调用 res.end() 之前不会发送,并且所有数据都是事件流立即发送。
response.writeHead(200, {
Connection: "keep-alive",
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Access-Control-Allow-Origin": '*',
'Content-Encoding':'identity' // this with and without this
});
let syncher= setInterval(() => {
if(response.finished){ // If response ended the interval is cleared
clearInterval(syncher);
return;
}else{
let dataToSend = getEventData(user,event);
if(! dataToSend ){
response.write('data:{close:true}');
clearInterval(syncher);
return;
}
response.write(`data:${JSON.stringify(dataToSend)}\n\n`);
response.flushHeaders(); // Also tried with response.flush()
if(dataToSend.close){
delEventData(user,event);
response.end();
}
}
}, 500);
Run Code Online (Sandbox Code Playgroud)
上面的代码位于服务器端,这也有关闭侦听器来关闭连接
const ev = new EventSource(conf.apiUrl+'/getStatus/'+ (userData.id || '') ); …
Run Code Online (Sandbox Code Playgroud) 在flask中,我有一个用于EventSource
接收更新/事件的页面。
它以相当简单的方式实现:
@route('/updates')
def updates():
def gen():
while True:
update = make_update()
yield "data: {0}\n\n".format(json.dumps(update))
return Response(stream_with_context(gen()), mimetype="text/event-stream")
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,每次我重新加载连接EventSource
到“更新”页面的页面时,它都会创建一个新线程来满足该“更新”请求。而且它永远不会死。
正在进行更新,因此这意味着它将数据推送到某个地方,从而使我的服务器使用越来越多的线程以及越来越多的内存。
我希望获得的简单解决方案是while True
用某种形式的替换while is_connected()
。
但是我似乎找不到找到检测浏览器是否仍处于连接状态的方法。
问题:如何在发生器内部检查连接是否仍然有效?
编辑
浏览代码似乎应该调用close()
generator,因此从理论上讲它应该GeneratorExit
在my中的某个位置抛出gen()
。
但是,我看不到有任何发生的痕迹,并且每次调用时,我都会看到pstree
在每次请求/连接后又产生一个条目/updates
。
为了开始使用EventSource
API,我编写了最学术的示例。问题是我总是遇到错误,而且找不到任何有用的信息。当我加载时home.html
,JS 脚本停止于source.onerror
; 我将其打印到控制台,但分析对象时我找不到任何错误类型或消息,所以我不知道它出了什么问题。代码有错误吗?可能是与服务器有关的错误?
home.html
<body>
<div id="result"></div>
<script src="sse.js"></script>
</body>
Run Code Online (Sandbox Code Playgroud)
sse.js
function isSseEnabled() {
return (typeof EventSource !== "undefined");
}
if (isSseEnabled()) {
var source = new EventSource('source.php');
source.onerror = function(e) {
console.log(e);
source.close();
};
source.onmessage = function (e) {
console.log(e.data);
document.getElementById('result').innerHTML += e.data.concat('<br>');
}
} else {
throw 'SSE not enabled';
}
Run Code Online (Sandbox Code Playgroud)
source.php
<?php
header('Content-Type: text/event-stream');
header('Cache-control: no-cache');
$time = date('r');
echo "Time: $time";
flush();
Run Code Online (Sandbox Code Playgroud) eventsource ×10
javascript ×3
php ×3
aws-lambda ×1
flask ×1
graphql ×1
gzip ×1
html ×1
java ×1
node.js ×1
python ×1
rspec ×1
ruby ×1
spring ×1
spring-mvc ×1
types ×1
typescript ×1
werkzeug ×1
wsgi ×1