1. 前言
可能是年底了的原因,大家工作效率都比较低,一个简单的需求评审会拖拖拉拉开了4个小时,无聊至极。趁这个机会整理一下最近正在思考的问题。服务端如何将数据推送到浏览器。
一般来说,Web
端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不websocket面试题容易,这里总结了4种方式。
1.websocket面试题 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');
})
前端监听XM安全LHttpRequest
的onreadystatechange
事件,每当源码之家服务器返回一段数据都会触发一次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
webso源码编辑器手机版下载cket
具有三个优点,双向通信,自动跨域,性能高。最源码编辑器下载主要的是可以传输多种格式的数据。WebSo源码编辑器手机版下载cket
协议在2008
年诞生,2011
年成为国际标准。所有浏览器都已经支持了,也是应用很广泛的一种即时通信协议。
websocket
是HTM前端和后端的区别L5
新增的API
,属于浏览器或者前端的内容。后端用的是socket
,socket
协议的历史相当古老基本四websocket面试题十年前就已经存在了。在H5
中webso源码编辑器cket安全工程师
自带一些安全前端和后端哪个工资高的措施,而原生前端面试题的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
请求到服务,会携带一个upgrade
为websocket
的请安全模式怎么解除求头,表示希望升级为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
只能服务器向浏览器发送数据,这点和第二种方式很像,能力上都不如wwebsocket菜鸟教程ebsocket
,优点是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-type
为text/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');
})
4. ajax
ajax源码网站
轮询,这个没啥好说的,是个实例化对象是什么意思人都想的安全到前端开发,就不介绍了。
没错,这条就是用来凑数的。安全