原文地址:
https://www.douyacun.com/article/d189d3d86915f5ff4c3be6a517570a0a
背景:之前开发的聊天是的功能,用的人太少了,考虑再三就决定去掉聊天室的功能了,改做一些其他有意思的事情,比如目前已经开发好了的左边栏当前在线人数,阅读时长统计(正在开发中)
遇到的问题:
页面虽然是react写的,但是nextjs服务端渲染的,不是单页应用就不能像单页应用那样有全局变量存储整站的websocket
服务端使用nginx作为代理服务器(之前是kong,后来干掉了),nginx proxy模块默认有 read_timeout/send_timeout 默认值 60s
服务端socket存储数据结构选型
实现思路:
因为是多页模式,就需要每个页面初始化一个wss连接,按cookie去重以后就是当前在线人数。
页面wss重联机制,毕竟断网是很常见的
* websocket: 初始化
const
connect
= (
) => {
conn =
new
WebSocket
(ws_address);
conn.
onmessage
= handlerMessage;
conn.
onclose
=
function
(
e
) {
console
.
log
(
'Socket is closed. Reconnect will be attempted in 1 second.'
, e.
reason
);
setTimeout
(
function
(
) {
connect
();
},
1000
);
conn.
onerror
=
function
(
e
) {
console
.
error
(
'Socket encountered error: '
, e.
message
,
'Closing socket'
);
conn.
close
()
nginx:proxy_read_timeout/proxy_send_timeout默认60s超时,心跳检测,只需要服务端在60s内定时发送ping(0x9)消息就可以了,浏览器会自动回复pong消息
for {
select {
case <-countTicker.C:
c.send <- c.hub.Count().Bytes()
case <-pingTicker.C:
_ = c.conn.SetWriteDeadline(time.Now().Add(writeWait))
if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
return
服务端存储socket结构体,没有向指定socket写数据的需求,不需要额外维护socket的数据结构,维护一个cookie在线页面数即可
type Hub struct {
uuid map[string]int
broadcast chan Responser
register chan *Client
unregister chan *Client
func (h *Hub) Run() {
for {
select {
case client := <-h.register:
h.uuid[client.uuid]++
client.send <- hub.Count().Bytes()
case client := <-h.unregister:
h.uuid[client.uuid]--
if h.uuid[client.uuid] == 0 {
delete(h.uuid, client.uuid)
安全方面需要考虑的内容是:
如何检测跨站点 WebSocket 劫持漏洞?
同一设备 ws 连接数如何限制,避免bug导致连接数过多导致服务挂掉?
解决方法:
check origin, 确保是自己网站的来源