服务器通过angularjs(和Play Framework)发送的事件在提交后继续重新启动
我正在尝试使用Angular.js单页应用程序构建SSE,并将Play Framework作为后端。似乎每次我使用angular的$http提交注册时,EventSource都会重新连接。 因为我试图使UI流平滑,所以在连接时,我添加了通过SSE推送数据的功能,它发送客户端获取并呈现的整个注册列表。在更新(注册新用户等)时,SSE将发送整个列表以及更改(添加的注册人等),客户端可以通过事件类型告知需要做什么(以及如果需要)(将新注册人添加到呈现的列表)。但是,由于某些原因,我一直在获取提交后的日期,而不是更新事件 下面的代码: SSE连接(在角度控制器-coffeescript符号中): 服务器端代码:服务器通过angularjs(和Play Framework)发送的事件在提交后继续重新启动,angularjs,playframework-2.0,server-sent-events,Angularjs,Playframework 2.0,Server Sent Events,我正在尝试使用Angular.js单页应用程序构建SSE,并将Play Framework作为后端。似乎每次我使用angular的$http提交注册时,EventSource都会重新连接。 因为我试图使UI流平滑,所以在连接时,我添加了通过SSE推送数据的功能,它发送客户端获取并呈现的整个注册列表。在更新(注册新用户等)时,SSE将发送整个列表以及更改(添加的注册人等),客户端可以通过事件类型告知需要做什么(以及如果需要)(将新注册人添加到呈现的列表)。但是,由于某些原因,我一直在获取提交后的日
def getSSE = Action { implicit request =>
Async {
Receiver.join map { join =>
Ok.feed(join._2 &> EventSource()).as("text/event-stream")
}
}
}
接收人:
class Receiver extends Actor {
val (enumerator, channel) = Concurrent.broadcast[JsValue]
def receive = {
case Connect => {
sender ! Connected(enumerator)
}
case Save(newOne) => {
MyDao.save(newOne) map { saved =>
sender ! ActionSuccess("New one Created", Some(saved))
self ! notifyAll("Added", Some(saved)
}
}
case NoOpUpdate(eventType, affectedOne) => {
notifyAll("NoOpUpdate: " + eventType, affectedOne)
}
}
def notifyAll(eventType: String, affectedOne: Option[Person]) {
MyDao.findAll map { people =>
val msg = JsObject(
Seq(
"type" -> JsString(eventType),
"affectedOne" -> Json.toJson(affectedOne),
"list" -> Json.toJson(people)
)
)
channel.push(msg)
}
}
}
object Receiver {
val default = Akka.system.actorOf(Props[Receiver])
implicit val timeout = Timeout(1 second)
def update(eventType: String, affectedOne: Option[Person] = None) {
default ! NoOpUpdate(eventType, affectedOne)
}
def join: Future[(Iteratee[JsValue,_],Enumerator[JsValue])] = {
default ? Connect map {
case Connected(enumerator) => {
val iteratee = Iteratee.foreach[JsValue]{ js =>
Json.stringify(js \ "type") match {
case "save" => {
Json.fromJson[Person](js \ "person").asOpt map { jsOpt =>
default ? Save(jsOpt)
}
}
case _ => {
}
}
}
(iteratee, enumerator)
}
}
}
MyDAO:
def save(person: Person): Future[Person] = {
collection.save(person).map {
case ok if ok.ok =>
person
case error => throw new RuntimeException(error.message)
}
}
def findAll: Future[Seq[Guardian]] = {
collection.find(Json.obj())
.sort(Json.obj("_id" -> -1))
.cursor[Guardian]
.toList
}
很多代码和一个很长的问题。有什么想法吗?不是100%确定它为什么要关闭,但看看这个:
$scope.serverListener.addEventListener('message', $scope.sseMessage, false)
您正在订阅类型为message
(类似于open
)的邮件。但是您发送的任何消息都没有发送类型(在JSON中设置名为type
的属性并不发送类型)。要发送类型,您需要实现一个play.api.libs.EventSource.EventNameExtractor
,它将从事件中提取名称。通常我会这样做:
然后我让我的枚举器成为这些事件类型的枚举器
另外,我希望您知道,您从未使用在join方法中创建的iteratee。也许你也在把它用于WebSocket,如果是这样的话,那没关系
不管怎样,要调试它关闭的原因。。。浏览器中开发人员控制台的“网络”选项卡上显示了什么
class Receiver extends Actor {
val (enumerator, channel) = Concurrent.broadcast[JsValue]
def receive = {
case Connect => {
sender ! Connected(enumerator)
}
case Save(newOne) => {
MyDao.save(newOne) map { saved =>
sender ! ActionSuccess("New one Created", Some(saved))
self ! notifyAll("Added", Some(saved)
}
}
case NoOpUpdate(eventType, affectedOne) => {
notifyAll("NoOpUpdate: " + eventType, affectedOne)
}
}
def notifyAll(eventType: String, affectedOne: Option[Person]) {
MyDao.findAll map { people =>
val msg = JsObject(
Seq(
"type" -> JsString(eventType),
"affectedOne" -> Json.toJson(affectedOne),
"list" -> Json.toJson(people)
)
)
channel.push(msg)
}
}
}
object Receiver {
val default = Akka.system.actorOf(Props[Receiver])
implicit val timeout = Timeout(1 second)
def update(eventType: String, affectedOne: Option[Person] = None) {
default ! NoOpUpdate(eventType, affectedOne)
}
def join: Future[(Iteratee[JsValue,_],Enumerator[JsValue])] = {
default ? Connect map {
case Connected(enumerator) => {
val iteratee = Iteratee.foreach[JsValue]{ js =>
Json.stringify(js \ "type") match {
case "save" => {
Json.fromJson[Person](js \ "person").asOpt map { jsOpt =>
default ? Save(jsOpt)
}
}
case _ => {
}
}
}
(iteratee, enumerator)
}
}
}
def save(person: Person): Future[Person] = {
collection.save(person).map {
case ok if ok.ok =>
person
case error => throw new RuntimeException(error.message)
}
}
def findAll: Future[Seq[Guardian]] = {
collection.find(Json.obj())
.sort(Json.obj("_id" -> -1))
.cursor[Guardian]
.toList
}
$scope.serverListener.addEventListener('message', $scope.sseMessage, false)