结合Server-sent events与 EventSource使用,实现服务端主动向客户端发送数据

这篇具有很好参考价值的文章主要介绍了结合Server-sent events与 EventSource使用,实现服务端主动向客户端发送数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当前解决服务端推送的方案有这几个:

  1. 客户端长轮询(不推荐使用)
  2. websocket双向连接
  3. iframe永久帧(不推荐使用)
  4. EventSource

长轮训虽然可以避免短轮训造成的服务端过载,但在服务端返回数据后仍需要客户端主动发起下一个长轮训请求,等待服务端响应,这样仍需要底层的连接建立而且服务端处理逻辑需要相应处理,不符合逻辑上的流程简单的服务端推送;

websocket连接相对而言功能最强大,但是它对服务器的版本有要求,在可以使用websocket协议的服务器上尽量采用此种方式;

iframe永久帧则是在在页面嵌入一个专用来接受数据的iframe页面,该页面由服务器输出相关信息,如,服务器不停的向iframe中写入类似的script标签和数据,实现另一种形式的服务端推送。不过永久帧的技术会导致主页面的加载条始终处于“loading”状态,体验很差。

HTML5规范中提供了服务端事件EventSource,浏览器在实现了该规范的前提下创建一个EventSource连接后,便可收到服务端的发送的消息,这些消息需要遵循一定的格式,对于前端开发人员而言,只需在浏览器中侦听对应的事件皆可。

相比较上文中提到的3中实现方式,EventSource流的实现方式对客户端开发人员而言非常简单,兼容性上出了IE系的浏览器(IE、Edge)外其他都良好;对于服务端,它可以兼容老的浏览器,无需upgrade为其他协议,在简单的服务端推送的场景下可以满足需求。在浏览器与服务端需要强交互的场景下,websocket仍是不二的选择。

客户端从服务器接受事件

服务器发送事件 API 也就是 EventSource 接口,在你创建一个新的 EventSource 对象的同时,你可以指定一个接受事件的 URI。例如:

const evtSource = new EventSource("ssedemo.php");

备注: 从 Firefox 11 开始,EventSource开始支持CORS.虽然该特性目前并不是标准,但很快会成为标准。

如果发送事件的脚本不同源,应该创建一个新的包含 URL 和 options 参数的EventSource对象。例如,假设客户端脚本在 example.com 上:

const evtSource = new EventSource("//api.example.com/ssedemo.php", { withCredentials: true } );

一旦你成功初始化了一个事件源,就可以对 message 事件添加一个处理函数开始监听从服务器发出的消息了:

evtSource.onmessage = function(event) {
  const newElement = document.createElement("li");
  const eventList = document.getElementById("list");

  newElement.innerHTML = "message: " + event.data;
  eventList.appendChild(newElement);
}

上面的代码监听了那些从服务器发送来的所有没有指定事件类型的消息 (没有event字段的消息),然后把消息内容显示在页面文档中。

你也可以使用addEventListener()方法来监听其他类型的事件:

evtSource.addEventListener("ping", function(event) {
  const newElement = document.createElement("li");
  const time = JSON.parse(event.data).time;
  newElement.innerHTML = "ping at " + time;
  eventList.appendChild(newElement);
});

这段代码也类似,只是只有在服务器发送的消息中包含一个值为"ping"的event字段的时候才会触发对应的处理函数,也就是将data字段的字段值解析为 JSON 数据,然后在页面上显示出所需要的内容。

页面代码案例:

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>测试</title>
</head>
<body>
<div>服务器端推送测试</div>
<div id="serverSendEventDiv"></div>
</body>
<script type="text/javascript">
    if(window.EventSource) {
        const source = new EventSource("push");
        let s = '';
        // 监听打开连接
        source.addEventListener('open', function (e) {
            console.log("连接打开")
        }, false);
        source.addEventListener('message', function (e) {
            s += e.data + '<br/>';
            document.getElementById("serverSendEventDiv").innerHTML = s;
        })
        // 监听关闭连接
        source.addEventListener('close', function (e) {
            if (e.readyState === EventSource.CLOSED) {
                console.log("连接关闭")
            } else {
                console.log(e.readyState)
            }
        }, false);
        source.addEventListener("error", function(err) {
            console.log(JSON.stringify(err))
            console.log(err)
            // 类似的返回信息验证,这里是实例
            err && err.status === 401 && console.log('not authorized')
        })
    } else {
        alert("你的浏览器不支持sse")
    }
</script>

服务器端如何发送事件流

服务器端发送的响应内容应该使用值为text/event-stream的 MIME 类型。每个通知以文本块形式发送,并以一对换行符结尾。有关事件流的格式的详细信息,请参见事件流格式。

官方文档给了一个php版本代码示例:

date_default_timezone_set("America/New_York");
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");

$counter = rand(1, 10);
while (true) {
  // Every second, send a "ping" event.

  echo "event: ping\n";
  $curDate = date(DATE_ISO8601);
  echo 'data: {"time": "' . $curDate . '"}';
  echo "\n\n";

  // Send a simple message at random intervals.

  $counter--;

  if (!$counter) {
    echo 'data: This is a message at time ' . $curDate . "\n\n";
    $counter = rand(1, 10);
  }

  ob_end_flush();
  flush();
  sleep(1);
}

上面的代码会让服务器每隔一秒生成一个事件流并返回,其中每条消息的事件类型为"ping",数据字段都使用了 JSON 格式,数组字段中包含了每个事件流生成时的 ISO 8601 时间戳。而且会随机返回一些无事件类型的消息。

java代码示例

package com.hj.ServerSendEvent;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
import java.util.Random;
 
/**
 * describe
 *
 * @author huangjuan
 * @date 2023/2/15 9:59
 */
@Controller
public class ServerSentEventController {
    @RequestMapping(value = "/push",produces = "text/event-stream")
    @ResponseBody
    public String pushToBrowser() {
        Random random = new Random();
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "data: server send event push message test:" + random.nextInt() + "\n\n";
    }
}

post的方式进行eventSource请求

new EventSource默认只支持get请求
用post的方式请求eventSource,常用的就是通过fetchEventSource这个库来实现
npm 仓库地址:https://www.npmjs.com/package/@microsoft/fetch-event-source

import { fetchEventSource } from '@microsoft/fetch-event-source';
const ctrl = new AbortController();
fetchEventSource('/api/sse', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        foo: 'bar'
    }),
    signal: ctrl.signal,
});

但是我的项目是简单的html项目,需要把npm包转换成js文件

npm包生成单个js文件并压缩

这里使用一个工具 browserify,
npm install -g browserify
使用 browserify main.js -o bundle.js

结合Server-sent events与 EventSource使用,实现服务端主动向客户端发送数据
压缩出来的js文件,有时需要把抛出来的方法挂在window下,然后在html里引入使用,看情况而定
如果要对js文件 压缩混淆

npm i browserify minify crypto-js
browserify -r crypto-js -s CryptoJS > crypto.js // -r 指定npm包名  -s 在代码中使用的模块名
minify crypto.js > crypto.mini.js // 压缩js文件

结合Server-sent events与 EventSource使用,实现服务端主动向客户端发送数据

请求失败后一直重新连接如何暂停

结合Server-sent events与 EventSource使用,实现服务端主动向客户端发送数据
结合Server-sent events与 EventSource使用,实现服务端主动向客户端发送数据
这个我在监听错误的回调里面 抛出了一个错误throw new Error(err),发现可以解决

fetchEventSource(`${this.baseUrl}/testurl`, {
method: 'GET',
	signal: that.abortController.signal,
	headers: {
		'Content-Type': 'application/json',
		'devicetype': 'pc',
		'token': that.token
	},
	async onopen(response) {
		if (response.ok) {
			console.log('连接了');
		} else {			
		}
	},
	onmessage(msg) {
		if (msg.event === 'FatalError') {
			throw new Error(msg.data);
		}
		if (msg.data !== '[DONE]') {
		}
	},
	onclose() {	
	},
	onerror(err) {
		throw new Error(err)
	}
});

参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events/Using_server-sent_events#%E4%BA%8B%E4%BB%B6%E6%B5%81%E6%A0%BC%E5%BC%8F

https://developer.mozilla.org/zh-CN/docs/Web/API/EventSource
https://blog.csdn.net/suwk1009/article/details/129323226
https://www.npmjs.com/package/@microsoft/fetch-event-source文章来源地址https://www.toymoban.com/news/detail-439796.html

到了这里,关于结合Server-sent events与 EventSource使用,实现服务端主动向客户端发送数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java Server-Sent Events通信

    后端可以向前端发送信息,类似于websocket,但是websocket是双向通信,但是sse为单向通信,服务器只能向客户端发送文本信息,效率比websocket高。 单向通信 :SSE只支持服务器到客户端的单向通信。这对于那些只需要服务器推送数据而无需客户端响应的场景非常有效,例如实时

    2024年01月23日
    浏览(41)
  • Java:SpringBoot整合SSE(Server-Sent Events)实现后端主动向前端推送数据

    SpringBoot整合SSE(Server-Sent Events)可以实现后端主动向前端推送数据 依赖 后端接收sse连接 前端浏览器代码 项目目录 完整依赖 pom.xml 前端代码 index.html 定义一个返回数据 Message.java 定义sse接口 SseService.java 实现sse接口 SseServiceImpl.java 定时任务 SendMessageTask.java 前端路由 IndexCont

    2024年02月10日
    浏览(42)
  • Server-Sent Events(以下简称 SSE)及event-source-polyfill使用单向长连接(后台主动向前端推送)

    SSE 与 WebSocket 作用相似,都是建立浏览器与服务器之间的通信渠道,然后服务器向浏览器推送信息SSE 是单向通道,只能服务器向浏览器发送,因为流信息本质上就是下载。如果浏览器向服务器发送信息,就变成了另一次 HTTP 请求 使用方法  Server-Sent Events 教程 - 阮一峰的网络

    2024年02月12日
    浏览(43)
  • ChatGLM-6B之SSE通信(Server-sent Events)

    写这篇博客还是很激动开心的,因为是我经过两周的时间,查阅各个地方的资料,经过不断的代码修改,不断的上传到有显卡的服务器运行才得出的可行的接口调用解决方案,在这里记录并分享一下。          起初领导让我写一个接口——前端传递用户问题,后端返回

    2024年02月06日
    浏览(35)
  • 前端Server-Sent Events(SSE)请求如何用post

    现在非常流行AI问答,AI回答的时候一般都是流式输出,一个字几个字几个字地慢慢加载完,要实现这个效果,我们一般可以用WebSocket和Server-Sent来实现。 我会选择使用SSE,为什么不用WebSocket呢? 1. WebSocket是双向通信,这个功能只需要服务器一直向我们输出。 2.SSE是一个htt

    2024年02月02日
    浏览(40)
  • Go 中的Server-Sent Events:一种高效的实时通信替代方案

    在当今的软件工程领域,实时通信在许多现代应用程序中发挥着至关重要的作用。Server-Sent Events (SSE) 是该领域广受欢迎的一项技术。 在本文中,我们将探讨Server-Sent Events 是什么,将它们的功能与 WebSocket 进行比较,提供 Go 和 JavaScript 代码示例,讨论使用服务器发送事件的优

    2024年02月11日
    浏览(42)
  • html5学习笔记19-SSE服务器发送事件(Server-Sent Events)

    https://www.runoob.com/html/html5-serversentevents.html 允许网页获得来自服务器的更新。类似设置回调函数。 demo_sse.php demo_sse.aspx

    2024年02月09日
    浏览(48)
  • SSE(Server-Sent Events,服务器推送事件)和sockets(套接字)通信区别

    SSE(Server-Sent Events,服务器推送事件)和sockets(套接字)都是用于实现实时通信的技术,但它们具有不同的特点和应用场景。 SSE 的优点: 简单易用:SSE 是基于HTTP协议的一种实时通信技术,使用简单,只需要在客户端通过EventSource对象监听服务器推送的事件即可。 可靠性:

    2024年02月15日
    浏览(50)
  • 浅谈PHP结合JavaScript SSE(Server Sent Events)实现服务器实时推送功能

    如配置后Nginx遇到502/504的,请参考这两篇文章的解决方案 PHP-FPM与Nginx通信报 502 Bad Gateway或504 Gateway Timeout终极解决方案(适用于PHP执行耗时任务情况下的报错) Linux系统下配置Nginx使部分URL使用多套自定义的PHP-FPM配置 SSE 的全称是 Server Sent Events,即服务器推送事件。它是一种

    2024年02月08日
    浏览(44)
  • java Server Sent Event 实现消息推送

    我选择的是Server-sent events),简称SSE。主要是我理解起来简单。 这个链接是介绍 几种消息推送的方式java实现web实时消息推送的七种方案--个人学习记录_java实时推送前端数据_自不惘的博客-CSDN博客  目前uniapp不支持EventSource,暂时就是pc端

    2024年02月11日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包