HTML5服务器推送消息的各种解决办法

本文深入探讨了多种服务器推送技术,包括AJAX轮询、Comet、Server-Sent Events及WebSocket等,介绍了它们的工作原理及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

AJAX

正常的一个页面在浏览器中是这样工作的:

  1. 用户向给予浏览器一个需要访问的地址
  2. 浏览器根据这个地址访问服务器,并与服务器之间创建一个TCP连接(HTTP请求)
  3. 服务器根据这个地址和一些其它数据,组建一段HTML文本,将写入TCP连接,然后关闭连接
  4. 浏览器得到了来自服务器的HTML文本,解析并呈现了浏览器上给用户浏览

此时,用户点击了网站上任何一个<a>或触发任何一个<form>提交时:

  1. 浏览器根据form的参数或者a的参数,作为访问的地址
  2. 与服务器创建TCP连接
  3. 服务器组建HTML文本,然后关闭连接
  4. 浏览器将当前显示的页面摧毁,并按照新的HTML文本呈现一个新的页面给用户

我们不难发现的是整个过程中间,一旦建立了一个连接,页面就无法再维护住了。整个过程看上去有点强买强卖,也许我只要一杯新的可乐,但你非要给我一整个套餐组合。

此时我们可以了解一下XmlHttpRequest组件,这个组件提供我们手动创建一个HTTP请求,发送我们想要的数据,服务器也可以只返回我们想要的结果,最大的好处是,当我们收到服务器的响应时,原来的页面没有被摧毁。这就好比,我喊一句"我的咖啡喝完了,我要续杯",然后服务员就拿了一杯咖啡过来,而不是会把我没吃完的套餐全部倒掉。

当我们利用AJAX实现服务器推送时,其实质是客户端不停地向服务器询问"有没有给我的消息呀?",然后服务器回答"有"或"没有"来达到的实现效果。它的实现方法也很简单,利用jQuery框架封装好的AJAX调用也很方便:

function getMessage(fn) {
    $.ajax({
        url: "Handler.ashx", //一个能够提供消息的页面
        dataType: "text",    //响应类型,可以是JSON,XML等其它类型
        type: "get",         //HTTP请求类型,还可以是post
        success: function (d, s) {
            fn(d);           //得到了正常的响应时,利用回调函数通知外部
        },
        complete: function (x, s) {
            setTimeout(function () {
                getMessage(fn);
            }, 5000);       //无论响应成功或失败,在若干秒后再询问一次服务器
        }
    });
}

 通过上面的代码,可以每隔5秒询问一次服务器是否有需要处理的消息,通过这种方式可以达到推送的效果,但是会存在一个问题:

  1. 间隔时间越快,推送的及时性越好,服务器的消费越大;
  2. 间隔时间越慢,推送的及时性越低,服务器的消费越小。

而且严格地来说,这种实际方式,并不是真正意义上的服务器主动推送消息,但由于早期技术手段缺乏,所以AJAX轮循成为了一种很普遍的手段。

 


 

 

Comet

我们知道HTTP请求其实是基于TCP连接实现的,再看看之前说的HTTP请求处理过程:

  1. 客户端与服务器建立TCP连接
  2. 服务器根据客户端提交的报文处理并生成HTML文本
  3. 将HTML封闭成为HTTP协议报文并返回给客户端
  4. 关闭链接。

看到这个处理过程,我们不难联想到,如果把第4步——关闭连接给省掉,那不就相当于有一个长连接一直被维持住了么。通过对服务端的一些操作,我们可以直接将数据从这个TCP连接发送客户端了。

通过这种技术,我们可以大大提高服务器推送的实时性,还可以减去服务端不停地建立、施放连接所形成的开销。

目前市面上有不少基于AJAX实现的Comet机制,但主要有两种方式:

  1. 建立连接后依然使用"询问"+"应答"的模式。虽然工作方式没变,但是因为减去了每次建立与施放连接的工作,所以性能上提升了很多。而且服务器对TCP连接可以有上下文的定义,而不像以前的AJAX完全是无状态的。
  2. 通过对Stream的写入实现服务器将数据主动发送到客户端。因为是TCP连接,所以通过对服务器的编程,我们可以主动的把数据从服务端发送给客户端,从模式上真正建立起了推送的概念。

 


 

 

Server-Sent

Server-Sent是HTML5提出一个标准,它延用了Comet的思路,并对其进行了一些规范。使得Comet这项技术由原来的分支衍生技术转成了正统的官方标准。

它的原理与Comet相同,由客户端发起与服务器之间创建TCP连接,然后并维持这个连接,至到客户端或服务器中的做任何一放断开,ServerSent使用的是"问"+"答"的机制,连接创建后浏览器会周期性地发送消息至服务器询问,是否有自己的消息。

这项标准不仅要求了支持的浏览器能够原生态的创建与服务器的长连接,更要求了对JavaScript脚本的统一性,使得兼程该功能的浏览器可以使用同一套代码完成Server-Sent的编码工作。

创建代码非常简单:

//定义一个ServerSent对象
var s = new EventSource("Handler.ashx");
//当收到一个非自定义事件时的回调函数
s.onmessage = function (e) {
    alert(e.data);
};
//当收到一个被服务器命名为MyEvent事件消息时的回调函数
s.addEventListener("MyEvent", function (e) {
    alert(e.data);
});

而服务器的代码也很简单:

public class Handler : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        context.Response.ContentType = "text/event-stream";
        context.Response.Expires = -1;
        context.Response.Write("event: MyEvent\r\n");       //事件类型,使用\r\n结尾
        context.Response.Write("data: HelloWorld!\r\n");    //事件数据,换行时使用\r\n,并在新行再加上data:
        context.Response.Write("data: I'm server!\n\n");    //事件数据结束,使用\n\n
        context.Response.Flush();                           //这里不能用End,否则是关闭连接的
    }

    public bool IsReusable
    {
        get
        {
            return true;
        }
    }

}

两小段代码,就已经具备了服务器消息推送了。

总得来说SeverSent就是HTML5规范下的Comet,具有更好的统一性,而且简单好用。

 

 


 

 

WebSocket

看名字就知道了,这是一个可以用在浏览器上的Socket连接。

这也是一个HTML5标准中的一项内容,他要求浏览器可以通过JavaScript脚本手动创建一个TCP连接与服务端进行通讯。

WebSocket不包含太多的额外功能,仅仅就是TCP连接的几项基本功能:建立,临时以及发送。

另外WebSocket使用了ws和wss协议,需要服务器有与之握手的算法才能将连接打开。

所以WebSocket相对于之前几种手段来说,其编码量是最大的,但由于没有其它的约束,因此它也可以自由地实现所有可能的功能。

即可以满足"问"+"答"的响应机制,也可以实现主动推送的功能。

与ServerSent相同,HTML5也对WebSocket调用的JavaScript进行规范,我们可以弄过很简单的一代码构建一个WebSocket连接

var ws = new WebSocket("ws://192.168.0.105:10080"); //连接服务器        

ws.onopen = function (event) { alert("已经与服务器建立了连接\r\n当前连接状态:" + this.readyState); };
ws.onmessage = function (event) { alert("接收到服务器发送的数据:\r\n" + event.data); };
ws.onclose = function (event) { alert("已经与服务器断开连接\r\n当前连接状态:" + this.readyState); };
ws.onerror = function (event) { alert("WebSocket异常!"); };

还可以通过send的方式发送消息

ws.send("Hello World");

WebSocket具有较为复杂的协议,需要在服务端做额外编程才能进行数据通讯。有关协议的详细内容,我会在以后的文章中进行解释。

 

WebSocket + MessageQueue

MessageQueue,简称MQ,也就是消息列队。是一种常常用于Tcp服务端的技术。通过生产和访问各种消息类型,MQ服务器会将生产者所生成的消息发给感兴趣的客户端。市面上有很多的MQ框架,比如:ActiveMQ。

ActiveMQ已经支持了WebSocket协议,也就意味着,WebSocket已经可以作为一个生产者或一个消费者,与MQ服务器连接。

开发者可以通过MQTT的JS脚本,连接上MQ服务器,同时将Web服务器也连上MQ服务器,从此可以告别了Http通讯协议,完完全全使用Socket通讯来完成数据的交换。

 


 

总结:

总得来说,在HTML5规范下,最推荐使用ServerSent和WebSocket的方式进行服务器消息的推送。

对比这两种方式。

ServerSent的方式,可以使服务端的开发依然依用以前的方式,但是其工作方式与Comet类似。

而WebSocket的方式,则对服务端的开发有着较高的要求,但其工作方式是完全的推送。

我本人其实挺偏向WebSocket + MQ的工作方式,但是对于老项目的翻新,还是用SeverSent比较好

 


结尾

本文为作者原创,转载请注明出处:http://www.cnblogs.com/ShimizuShiori/p/5464063.html

文章中的相关代码可以在 http://j.zizhusoft.com/Develop/Explorer.aspx 中的ServerSent目录中查看

<think>好的,用户的问题是关于如何使用HTML和JavaScript与MediaMTX进行录制。首先,我需要理解MediaMTX是什么。根据之前的知识,MediaMTX是一个开源的媒体服务器,支持RTSP、RTMP、HLS等协议,常用于视频流的传输和处理。用户可能希望在自己的网页应用中实现录制功能,所以需要结合前端技术(HTML/JS)和MediaMTX的API。 接下来,我需要回忆之前提供的引用内容。引用[1]提到检查MediaRecorder和navigator.getUserMedia是否存在,这可能涉及到浏览器的媒体录制API。引用[2]提到数据管理,但可能和这个问题关系不大。引用[3]是关于模型性能的,可能也不相关。因此,重点应该放在引用[1]和MediaMTX的集成上。 用户的需求是录制,可能需要通过浏览器获取用户的媒体输入(如摄像头或麦克风),然后将流传输到MediaMTX服务器,并触发录制。但MediaMTX本身是否支持通过HTTP API控制录制?可能需要查阅MediaMTX的文档,确认其是否有相关的API端点来开始和停止录制。 然后,考虑前端的实现步骤:首先使用WebRTC通过getUserMedia获取媒体流,然后使用MediaRecorder API进行录制,或者将流传输到MediaMTX服务器,再通过服务器端进行录制。但用户的问题是如何使用HTML/JS与MediaMTX实现录制,所以可能需要结合两者。 可能的流程是:浏览器捕获媒体流,通过WebSocket或HTTP将流发送到MediaMTX,然后调用MediaMTX的API开始录制。但需要确认MediaMTX是否支持这样的操作。另一种方法是使用MediaMTX作为中继服务器,将流推送到它,然后服务器端进行录制,这时候前端只需要处理推送流的部分。 需要分步骤解答:1. 在HTML/JS中捕获媒体设备;2. 将流传输到MediaMTX;3. 触发MediaMTX的录制功能。同时,可能需要使用fetch或XMLHttpRequest来调用MediaMTX的API接口,比如发送POST请求到特定端点开始录制。 还需要注意跨域问题,确保MediaMTX服务器配置了CORS,允许前端应用访问其API。此外,安全性方面,可能需要认证令牌或API密钥,这取决于MediaMTX的配置。 最后,生成相关问题,比如如何配置MediaMTX、如何处理录制文件等,帮助用户进一步了解相关知识。</think>以下是使用HTML和JavaScript与MediaMTX实现录制的分步解决方案: --- ### 1. 基础环境准备 确保MediaMTX服务器已启动并配置了录制功能(默认支持RTSP/RTMP推流录制)。例如在`mediamtx.yml`配置文件中启用录制: ```yaml record: true recordPath: ./recordings ``` ### 2. 浏览器端媒体捕获 通过`navigator.mediaDevices.getUserMedia`获取音视频流: ```html <video id="preview" autoplay muted></video> <button onclick="startRecording()">开始录制</button> <button onclick="stopRecording()">停止录制</button> <script> let mediaStream; async function startRecording() { try { mediaStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true }); document.getElementById('preview').srcObject = mediaStream; } catch (e) { console.error("设备访问失败:", e); } } </script> ``` [^1] ### 3. 使用WebSocket推流到MediaMTX 通过WebRTC或WebSocket传输媒体流到MediaMTX服务器: ```javascript const ws = new WebSocket('ws://your-mediamtx-server:8889/streamname'); function sendMediaData(data) { if (ws.readyState === WebSocket.OPEN) { ws.send(data); } } // 使用MediaRecorder捕获数据 let mediaRecorder; function startStreaming() { mediaRecorder = new MediaRecorder(mediaStream); mediaRecorder.ondataavailable = (e) => { sendMediaData(e.data); }; mediaRecorder.start(1000); // 每1秒发送一次数据块 } ``` ### 4. 控制录制启停 通过HTTP API控制MediaMTX的录制操作: ```javascript // 开始录制 fetch('http://your-mediamtx-server:9997/v2/record/start/streamname', { method: 'POST' }); // 停止录制并保存文件 fetch('http://your-mediamtx-server:9997/v2/record/stop/streamname', { method: 'POST' }); ``` ### 5. 完整集成示例 ```html <!DOCTYPE html> <body> <video id="preview" width="640" height="480" autoplay muted></video> <button onclick="toggleRecording()">Toggle Record</button> <script> let isRecording = false; let mediaRecorder; const ws = new WebSocket('ws://localhost:8889/mystream'); async function toggleRecording() { if (!isRecording) { const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true}); document.getElementById('preview').srcObject = stream; mediaRecorder = new MediaRecorder(stream); mediaRecorder.ondataavailable = e => ws.send(e.data); mediaRecorder.start(1000); // 通知MediaMTX开始存储 await fetch('http://localhost:9997/v2/record/start/mystream', {method: 'POST'}); isRecording = true; } else { mediaRecorder.stop(); await fetch('http://localhost:9997/v2/record/stop/mystream', {method: 'POST'}); isRecording = false; } } </script> </body> </html> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值