JavaScript实现即时通讯的 4 种方案

目录
  • 前言:
  • 1. http + ajax
  • 2. websocket
  • 3. SSE

前言:

服务端如何将数据推送到浏览器,一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,这里总结了4种方式。

1. http + ajax

XMLHttpRequest在和服务端进行数据交互时存在四种状态,很多时候的判断是readyState为4时,从response获取服务端响应结果。其实readyState等于3的时候就可以获取到服务端的部分数据了。

可以利用这个属性实现服务端推送。

比如服务使用http创建服务,每间隔1s的时候通过write方法返回一段文本,但是不要调用end方法。

const http = require('http');
const fs = require('fs');

const app = http.createServer((req, res) => {
    // 设置响应头
    res.setHeader('Content-type', 'application/json; charset=utf-8');
    res.setHeader('Cache-Control', 'max-age=0'); // 没有缓存
    let num = 0;
    // 地柜返回
    const send = () => {
        if (num > 20) {
            res.end();
            return;
        }
        num++;
        const data = Math.random() + '';
        res.write(data, 'utf8');
        setTimeout(send, 1000);
    }
    send();
});

app.listen(8081, () => {
    console.log('127.0.0.1:8081');
})

前端监听XMLHttpRequestonreadystatechange事件,每当服务器返回一段数据都会触发一次onreadystatechange事件,可以从responseText中得到当前获取到的全部数据。

var xhr = new XMLHttpRequest();
xhr.open('GET', '/api');
xhr.timeout = 30000;
xhr.responseType = 'text';
xhr.onreadystatechange = function () {
    if (this.readyState == 3) { // 分段获取服务端返回的数据
        console.log(this.responseText);
    }
    if (this.readyState == 4) {
        if (this.status >= 200 && this.status < 300 || this.status == 304) {
            // this.response
        } else {
            // this.statusText
        }
    }
}
xhr.send()

2. websocket

websocket具有三个优点,双向通信,自动跨域,性能高。最主要的是可以传输多种格式的数据。WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了,也是应用很广泛的一种即时通信协议。

websocket是HTML5新增的API,属于浏览器或者前端的内容。后端用的是socket,socket协议的历史相当古老基本四十年前就已经存在了。在H5中websocket自带一些安全的措施,而原生的socket就没什么安全性可言了。

客户端浏览器通过实例化Websocket,传入服务地址创建websocket链接,message中会接收到服务端推送的数据,也可通过send方法向服务端发送数据。

const ws = new Websocket('ws://127.0.0.1:8080/api');
// 原生没有emit,自己封装一个
ws.emit = function(name, ...args) {
    ws.send(JSON.stringify({
        name,
        data: [...args]
    }))
}
ws.onopen = function() {
    console.log('链接上了');
    // ws.send('dadadadadasda'); // 发送数据,只有一个参数一个大字符串
    ws.emit('msg', 12, 5, 8);
}; // 已经链接
ws.onmessage = function() {
    console.log('接收到消息了')
}; // 收到数据
ws.onclose = function() {
    console.log('断开链接了')
}; // 断开了

node中想要实现socket可以借助node原生的net模块,这是一个相对底层的网络模块,是一个tcp的库。net是http的底层,很多东西都需要自己去实现,比如这里可以使用net.createServer来创建服务。

websocket也是给予http的,先通过http请求到服务,会携带一个upgradewebsocket的请求头,表示希望升级为websocket,这个时候服务可以返回101状态码,表示进行服务可以升级。

const http = require('http');
const net = require('net'); // TCP的库,可以理解为原生的Socket
const crypto = require('crypto'); // 借助加密库实现一些安全性

const server = net.createServer(sock=> {
    console.log('链接上了');
    sock.on('end', () => {
        console.log('客户端断开了')
    }); // 断开

    sock.once('data', (data) => {
        console.log('hand shake start...');
        // 最先过来的是http头
        const str = data.toString();
        // 将http头用\r\n切开
        let lines = str.split('\r\n');
        // 删除第一行和最后一行,因为没啥用
        lines = lines.slice(1, lines.length - 2);
        // 将所有请求头通过'分号空格'切开
        const headers = {};
        lines.forEach(line => {
            const [key, value ] = line.split(': ');
            // 将请求头变成小写
            headers[key.toLowerCase()] = val;
        })
        // http协议转websocket会传入upgrade为websocket
        if (headers['upgrade'] != 'websocket') {
            console.log('其他协议,暂不支持');
            sock.end();
        } else if (headers['sec-websocket-version'] != 13) {
            console.log('不兼容不是13的版本');
            sock.end();
        } else {
            const key = headers['sec-websocket-key'];
            // 13版本的源码是258E,可以百度的到
            const mask = '258EAFA5-47DA-95CA-C5AB0DC85B11';
            // 需要把key和mask加在一起,然后用sha1加密,再变成base64,还给客户端
            // sha1(key + mask) -> base64 -> client;
            const hash = crypto.createHash('sha1');
            hash.update(key + mask);
            const tokey = hash.digest('base64');
            // 数据以HTTP发回客户端,因为验证的过程还是http阶段, 状态值为101(正在切换协议,协议升级 Switching Protocols)
            sock.write('HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ' + tokey + '\r\n'); // Upgrade: websocket告诉浏览器升级为websocket,冒号要有空格
            // 至此,握手已经结束了。因为握手的过程只有一次,所以不要用on处理,用once处理
            // 从这里开始,才是真正的数据,以后所有的数据都走这里,所以用on处理
            sock.on('data', data => {
                // 获取到的数据
                // 不过数据是一个buffer的数据包,解析起来比较麻烦。
                console.log(data);
            })
        }
    }); // 有数据过来
}).listen(8080);

上面介绍的是websocket的一个实现原理,项目中可以直接使用socket.io这个库。

前端代码如下:

const sock = io.connect('ws://127.0.0.1:8080/api');
sock.on('connect', () => {
    console.log('已链接');
    sock.emit('aaa', 12, 5,8);
    sock.on('time', (ts) => {
        console.loh(ts);
    })
});
sock.on('disconnect', () => {
    console.log('已断开');
});

服务端代码如下:

const http = require('http');
const io = require('socket.io');

// 创建http服务,开启8080端口号
const httpServer = http.createServer().listen(8080);
// socket监听http服务
const wsServer = io.listen(httpServer);

// 当有链接的时候
wsServer.on('connection', sock => {
    // 发送
    // sock.emit
    sock.emit('time', Date.now());
    // 接收
    sock.on('aaa', (a, b, c) => {
        console.loh(a, b, c);
    })
})

3. SSE

SSE全称是Server-Sent Events,指的是网页自动获取来自服务器的更新,也就是自动获取服务端推送至网页的数据,这是一个H5的属性,除了IE,其它标准浏览器基本都兼容。

实现方式和第二种有一些像,服务器向客户端声明要发送流信息,然后连续不断地发送过来。这时客户端是不会关闭连接的,会一直等着服务器发过来的新的数据流。比如音视频的媒体流就是这种机制。

SSE 只能服务器向浏览器发送数据,这点和第二种方式很像,能力上都不如websocket,优点是SSE使用更加简单,并且基于http协议,兼容性还可以(当然2022年了,没有啥是兼容性不可以的了)。

H5端使用EventSource对象,填入要请求的url地址就可以了。

var source = new EventSource('/api', {
    withCredentials: true
});
source.onopen = function () {
    console.log('链接已建立', this.readyState);
}
source.onmessage = function (event) {
    console.log('实时获取的数据', event.data);
}
source.onerror = function () {
    console.log('发生错误');
}
// 关闭
// source.close();

服务器向浏览器发送的 SSE 数据,首先必须设置响应头的Content-typetext/event-stream,且编码格式为utf-8。返回的数据格式必须为data: xxxx\n\n。除了data还有event,id,以及retry,可以参考Server-sent_events-mdn

服务端代码如下:

const http = require('http');
const fs = require('fs');

const app = http.createServer((req, res) => {
    res.setHeader('Content-type', 'text/event-stream; charset=utf-8');
    res.setHeader('Cache-Control', 'max-age=0'); // 清楚缓存
    res.setHeader('Access-Control-Allow-Origin', 'http:127.0.0.1/');
    let num = 0;
    const send = () => {
        if (num > 20) {
            res.end();
            return;
        }
        num++;
        const data = Math.random() + '';
        res.write(`data: ${data}\n\n`, 'utf8');
        setTimeout(send, 1000);
    }
    send();
});

app.listen(8081, () => {
    console.log('127.0.0.1:8081');
})

到此这篇关于JavaScript实现即时通讯的 4 种方案的文章就介绍到这了,更多相关JavaScript实现即时通讯方案内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • NodeJs 实现简单WebSocket即时通讯的示例代码

    服务器的实现很简单,先装一个nodeJs的模块,叫nodejs-websocket , 直接在nodeJs命令行中敲入:npm install nodejs-websocket回车就可以安装好了,然后就可以开始建立服务器了,因为有了nodejs-websocket模块,所以很多工作都不用我们自己做,直接调用别人封装好的方法就行了: 服务端代码 根据客户端传来的消息判断哪个是game1,哪个是game2,保存connection对象. var ws = require("nodejs-websoc

  • nodejs结合Socket.IO实现的即时通讯功能详解

    本文实例讲述了nodejs结合Socket.IO实现的即时通讯功能.分享给大家供大家参考,具体如下: 动态web 在html5以前,web的设计上并没有考虑过动态,他一直是围绕着文档设计的,我们看以前比较老的网站,基本上都是某一刻用来显示单一的文档的,用户请求一次web页面,获取一个页面,但是随着时间的推移,人们想要web做更多的事情了,而不是简单的要显示文档,而javaScript一直处于开发人员推动web页面功能的发展中心. Ajax无疑是动态Web页面的一个重大发展,他不再需要我们即使更新

  • 在Node.js下运用MQTT协议实现即时通讯及离线推送的方法

    前言 前些日子了解到mqtt这样一个协议,可以在web上达到即时通讯的效果,但网上并不能很方便地找到一篇目前版本的在node下正确实现这个协议的博客. 自己捣鼓了一段时间,理解不深刻,但也算是基本能够达到使用目的. 本文尚未对离线消息的接收顺序进行处理. 代码 服务端: server.js //服务端引入中间件mosca let mosca = require('mosca') let settings = { port: 5112 } let server = new mosca.Server

  • nodejs和react实现即时通讯简易聊天室功能

    npx create-react-app socketio-demo 进入socketio-demo目录 运行eject进行拆包,本项目也可以不拆,这是个人习惯. 注意如果运行eject命令最好在项目初始阶段执行,已经开始编写后不要再使用容易出现bug,新人谨慎使用eject命令 yarn eject 项目拆包后创建服务器文件夹和文件 mkdir server type null>index.js 创建完成后目录如下 编写即时通讯(聊天室)后台 安装nodejs插件 npm i express

  • nodejs结合Socket.IO实现websocket即时通讯

    目录 为什么要用 websocket Socket.io 开源项目 效果预览 app.js index.html 为什么要用 websocket websocket 是一种网络通信协议,一般用来进行实时通信会使用到. websocket 协议和 http 协议类似,http 协议有一个缺陷,只能由客户方端发起请求,服务端根据请求 url 和传过去的参数返回对应结果 websocket 是双向通信的,只要 websocket 连接建立起来,可以由客户端给服务端发送数据,也可以由服务端主动给客户端发

  • JavaScript实现即时通讯的 4 种方案

    目录 前言: 1. http + ajax 2. websocket 3. SSE 前言: 服务端如何将数据推送到浏览器,一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,这里总结了4种方式. 1. http + ajax XMLHttpRequest在和服务端进行数据交互时存在四种状态,很多时候的判断是readyState为4时,从response获取服务端响应结果.其实readyState等于3的时候就可以获取到服务端的部分数据了. 可以利用这个属性实现服务端

  • Android Socket接口实现即时通讯实例代码

    Android Socket接口实现即时通讯 最近学习Android 通信的知识,做一个小实例,巩固下学习内容,以下内容是网上找的资料,觉得很不错,知识比较全面,大家看下. 首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.

  • 详解android环境下的即时通讯

    首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.在线代理.离线代理.离线扩展.在线直传指不经过服务器,直接实现点对点传输.在线代理指消息经过服务器,在服务器实现中转,最后到达目标账号.离线代理指消息经过服务器中转到达目标账

  • JavaScript 中断请求几种方案详解

    目录 1 Promise 中断调用链 中断Promise 包装abort方法--仿照Axios的CancelToken 2 RXJS的unsubscribe方法 3 Axios的CancelToken 1 Promise Promise有一个缺点是一旦创建无法取消,所以本质上Promise是无法被终止的. 但是我们可以通过中断调用链或中断Promise来模拟请求的中断. 中断调用链 中断调用链就是在某一个then/catch执行之后,后续的链式调用(包括then,catch,finally)不再

  • java实现web实时消息推送的七种方案

    目录 引言 什么是消息推送(push) 短轮询 长轮询 iframe流 SSE (我的方式) MQTT Websocket 自定义推送 Github地址 引言 做了一个小破站,现在要实现一个站内信web消息推送的功能,对,就是下图这个小红点,一个很常用的功能. 不过他还没想好用什么方式做,这里我帮他整理了一下几种方案,并简单做了实现. 案例下载 什么是消息推送(push) 推送的场景比较多,比如有人关注我的公众号,这时我就会收到一条推送消息,以此来吸引我点击打开应用. 消息推送(push)通常是

  • Laravel构建即时应用的一种实现方法详解

    即时交互的应用 大家应该都有所体会,在现代的 Web 应用中很多场景都需要运用到即时通讯,比如说最常见的支付回调,与三方登录.这些业务场景都基本需要遵循以下流程: 客户端触发相关业务,并产生第三方应用的操作(比如支付) 客户端等待服务端响应结果(用户完成第三方应用的操作) 第三方应用通知服务端处理结果(支付完成) 服务端通知客户端处理结果 客户端依据结果做出反馈 (跳转到支付成功页面) 在过去,为了实现这种即时通讯,能让客户端正确响应处理结果,最为常用的技术就是轮询,因为 HTTP 协议的单向性

  • 使用WebSocket实现即时通讯(一个群聊的聊天室)

    随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据. 传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据:这种客户端是主动方,服务端是被动方的传统Web模式对于信息变化不频繁的Web应用来说造成的麻烦

  • koa socket即时通讯的示例代码

    前言 http的特点是一问一答,而即时通讯是需要双向通信的,这样以前的即时通信只能使用轮询的方式通过周期性的ajax请求获取数据,直到websocket出现,就完美实现了双向通信 一 即时通讯方式简介 段轮询 前台使用setInterval进行定时请求后台,这样无疑非常浪费性能 长轮询和长连接(html5的EventSource) 客服端连接一次,服务端不断开连接,服务端接收到新消息就发送给前台,客服端和服务端保持一直连接,缺点是只有服务端向客服端输出 websocket websocket不再

  • Android即时通讯设计(腾讯IM接入和WebSocket接入)

    目录 一.前言 二.腾讯IM接入 1.准备工作 2.初始化工作 用户登录 3.群聊相关 4.消息收发相关 三.WebSocket接入 1.WebSocket介绍 2.服务端相关 3.客户端相关 四.列表设计的一些细节 1.handle的使用 2.消息的获取和RecycleView的刷新 3.关于消息item的设计细节 五.项目使用的接口和地址 六.总结 一.前言 之前项目的群聊是用数据库直接操作的,体验很差,消息很难即时反馈,所以最后考虑到了使用腾讯的IM完成群聊的接入,不过中途还是有点小坎坷的

随机推荐