1. Введение
Может быть, это конец года, эффективность работы у всех относительно низкая, простое рассмотрение требований затянется на 4 часа, что крайне скучно. Воспользуйтесь этой возможностью, чтобы разобраться, о чем вы думали в последнее время. Как сервер отправляет данные в браузер.
Вообще говоря,Web
Сквозную технологию обмена мгновенными сообщениями всегда было сложно внедрить из-за конструктивных ограничений браузеров. Вот четыре метода.
1. http + ajax
XMLHttpRequest
При взаимодействии с сервером есть четыре состояния.Во многих случаях суждениеreadyState
для4
когда, изresponse
Получите результат ответа сервера. фактическиreadyState
равный3
Когда вы можете получить некоторые данные с сервера.
Это свойство можно использовать для реализации push-уведомлений на стороне сервера.
например, использование услуг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');
})
внешний мониторингXMLHttpRequest
из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
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
Запрос на обслуживание, будет нести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
Только сервер может отправлять данные в браузер, что очень похоже на второй метод, но не так эффективно.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-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
Опрос, по этому поводу нечего сказать, это все так думают, поэтому не буду вводить.
Правильно, это для составления чисел.