socket.io
Socket.IO is an open source framework implemented entirely by JavaScript, based on Node.js, and supporting WebSocket protocols for real-time communication, cross-platform. It includes JavaScript on the client side and Node.js on the server side.
The service side
Basic use based on KOA and socket. IO
const koa = require('koa')
const app = new koa()
const server = require('http').createServer(app.callback())
const io = require('socket.io')(server) // Listen for the connect event IO. On ('connection', socket => {
socket.emit('open'); // Notify the client that console.log('connected'); // Listen to the disconnect event socket.on('disconnect', () => {
console.log('disconnect')}}); server.listen(3001);Copy the code
The client
import io from 'socket.io-client'; // establish webSocket connection const socket = IO ('http://127.0.0.1:3001'); // Receive server connection acknowledgement socket.on('open', () => {
showTip('socket io is open ! ');
init();
});
Copy the code
socket.io
practice
Blog address
Test account: admin
Test password: admin
Please click on the “Testing socket. IO functionality” detail comment article to see how it works
The service side
1. Write the tool function startWebSocketApp and webSocketObj instance export
const roomPrefix = 'user_'; const webSocketObj = { noticeRooms: {}, webSocketIo: Null, // Send a message sendNotice(userId, data) {const {noticeRooms, webSocketIo} = this; const keys = Object.keys(noticeRooms);if(! userId || ! webSocketIo || ! keys.length || ! data) {return} const sockets = webSocketIo.sockets.sockets; Room const currentSocket = sockets[noticeRooms['${roomPrefix}${userId}`]].if(currentSocket) {// emit notification currentsocket.emit (currentSocket)'getNotice', data); }}, // Send the global system message sendSystemNotice(data) {const {noticeRooms, webSocketIo} = this; const keys = Object.keys(noticeRooms);if(! data || ! webSocketIo || ! keys.length) {return} const sockets = this.webSocketIo.sockets.sockets; // keys = keys.filter(key => noticeRooms[key] ! == socket.id); keys.forEach(key => { const currentSocket = sockets[noticeRooms[key]];if (currentSocket) {
currentSocket.emit('getNotice', data); }}); }}; const startWebSocketApp = server => { const webSocketIo = webSocketObj.webSocketIo = require('socket.io')(server, {path: '/notice'}); const {noticeRooms} = webSocketObj; //webSocket listening method webSocketio.on ('connection', socket => {
console.log('Initialization successful! Now we can bind and trigger events using sockets.);
socket.on(`joinNoticeRoom`, data => {
console.log('Join the room:', data); // Record the current room ID noticeRooms[' user_] based on the current user ID${data}`] = socket.id;
});
});
};
module.exports = {startWebSocketApp, webSocketObj};
Copy the code
2. Global application tool function startWebSocketApp
const {startWebSocketApp} = require('./server/utils/web-socket');
const app = new Koa();
const server = require('http').Server(app.callback()); // Start webSocket startWebSocketApp(server); server.listen(config.port, () => { console.log(`starting at port:${config.port}`);
});
Copy the code
3. Database table design
- Table of Sending and receiving relationships (Message)
CREATE TABLE IF NOT EXISTS `message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sendId` int(11) DEFAULT NULL COMMENT 'Sender ID',
`recId` int(11) DEFAULT NULL COMMENT 'Recipient ID (all users when recId is 0)',
`messageId` int(11) DEFAULT NULL COMMENT 'the message content id',
`createDate` varchar(50) DEFAULT NULL COMMENT 'Send date',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Copy the code
- Send message table (message_content)
CREATE TABLE IF NOT EXISTS `message_content` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`type` int(11) NULL DEFAULT NULL COMMENT '10: Article comment 20: Article Comment Reply (Business scalable) ',
`title` varchar(255) DEFAULT NULL COMMENT 'Comment Subject',
`sourceId` int(11) NULL DEFAULT NULL COMMENT 'Comment source ID',
`content` longtext DEFAULT NULL COMMENT 'content',
`createDate` varchar(50) DEFAULT NULL COMMENT 'Send date',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Copy the code
- User message relationship table (message_user)
CREATE TABLE IF NOT EXISTS `message_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userId` int(11) DEFAULT NULL COMMENT 'user id',
`messageId` int(11) DEFAULT NULL COMMENT 'information id',
`status` int(11) NULL DEFAULT 10 COMMENT '(10: read)',
`createDate` varchar(50) DEFAULT NULL COMMENT 'Reading Date',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Copy the code
4. Specific use
- Each time a message is sent, insert a piece of data into the message_Content table to get the message_ID.
- The message table records fields such as sender, receiver, and message_ID. (If recId is 0, the message notification is sent to all users, avoiding the impact of inserting n pieces of data at a time.)
- After reading, the user inserts a piece of data into the message_user table to indicate that he or she has read. (If he or she has read, he or she must join the Message_user table instead of stuffing all the data in.)
5. Create a notice SQL statement method
const notice = {
async createMessageContent(data) {
const sqlStatement = `insert into ${MESSAGE_CONTENT} (type, title, content, sourceId, createDate) values (? ,? ,? ,? ,?) `; const {type, title, content, sourceId} = data;
const currentDate = formatDate(new Date());
return query(sqlStatement, [type, title, content, sourceId, currentDate])
},
async createMessage(data) {
const sqlStatement = `insert into ${MESSAGE}(sendId, recId, messageId, createDate) values (? ,? ,? ,?) `; const {sendId, recId, messageId} = data; const currentDate = formatDate(new Date());return query(sqlStatement, [sendId, recId, messageId, currentDate])
},
async createMessageUser(data) {
const sqlStatement = `insert into ${MESSAGE_USER}(userId, messageId, createDate) values (? ,? ,?) `; const {userId, messageId} = data; const currentDate = formatDate(new Date());return query(sqlStatement, [userId, messageId, currentDate])
},
async batchCreateMessageUser(values) {
const sqlStatement = `insert into ${MESSAGE_USER}(userId, messageId, createDate) values ? `;return query(sqlStatement, [values])
},
async getUnreadMessageList(id) {
const sqlStatement = `
SELECT
NOTICE_CONTENT.*,
USER.profilePicture,
USER.username sendName
FROM
(
SELECT
MESSAGE_CONTENT.*,
MESSAGE_USER.STATUS
FROM
(
SELECT
MESSAGE.sendId,
MESSAGE.recId,
MESSAGE.messageId,
CONTENT.*
FROM
( SELECT * FROM message WHERE recId = ${id} ) MESSAGE
LEFT JOIN message_content CONTENT ON MESSAGE.messageId = CONTENT.id
) MESSAGE_CONTENT
LEFT JOIN message_user MESSAGE_USER ON MESSAGE_CONTENT.messageId = MESSAGE_USER.messageId
WHERE
STATUS IS NULL
) NOTICE_CONTENT
LEFT JOIN user_info USER ON NOTICE_CONTENT.sendId = USER.id
`;
returnquery(sqlStatement); }}; module.exports = notice;Copy the code
6. Create a notice Controller method
const notice = {
async createNotice(data) {
const {sendId, recId, content, title, type.sourceId} = data;
const messageContentRes = await noticeSql.createMessageContent({content, title, type.sourceId});
if (messageContentRes && messageContentRes.insertId) {
const messageId = messageContentRes.insertId;
const messageRes = await noticeSql.createMessage({sendId, recId, messageId});
if (messageRes && messageRes.insertId) {
const userList = await userSql.getAllUserList();
if (userList && userList.length) {
const sendName = userList.find(user => user.id === sendId).username;
const noticeResult = {sendName, content, title, type};
if (recId === 0) {
webSocketObj.sendSystemNotice(noticeResult)
} else {
webSocketObj.sendNotice(recId, noticeResult)
}
} else{console.log(' user table does not exist or user does not exist, Cannot send notification ')}}}}, async getUnreadMessageList(CTX) {const authorization = ctX.header.authorization; const userInfo = await getTokenResult(authorization); const {id} = userInfo; const response = createResponse(); const unreadMessageList = await noticeSql.getUnreadMessageList(id);if (unreadMessageList && unreadMessageList.length) {
response.code = 0;
response.message = 'success';
response.results = unreadMessageList;
}else {
response.code = 404;
response.message = 'Information does not exist';
}
ctx.body = response;
},
async createMessageUser(ctx) {
const authorization = ctx.header.authorization;
const userInfo = await getTokenResult(authorization);
const requestBody = ctx.request.body;
const {id} = userInfo;
const {messageId} = requestBody;
const response = createResponse();
const res = await noticeSql.createMessageUser({messageId, userId: id});
if(res && res.insertId ! == undefined) { response.message ='success';
}
ctx.body = response;
},
async batchCreateMessageUser(ctx) {
const authorization = ctx.header.authorization;
const userInfo = await getTokenResult(authorization);
const requestBody = ctx.request.body;
const {id} = userInfo;
const {messageIdList} = requestBody;
const currentDate = formatDate(new Date());
const sqlValues = messageIdList.map(messageId => [id, messageId, currentDate]);
const response = createResponse();
const res = await noticeSql.batchCreateMessageUser(sqlValues);
if(res && res.insertId ! == undefined) { response.message ='success'; } ctx.body = response; }}; module.exports = notice;Copy the code
7. Add a Notice server route
const Router = require('koa-router');
const noticeModel = require('.. /controller/notice');
const notice = new Router();
notice
.get('/message-un-read', async ctx => noticeModel.getUnreadMessageList(ctx))
.post('/message-read', async ctx => noticeModel.createMessageUser(ctx))
.post('/message-read-batch', async ctx => noticeModel.batchCreateMessageUser(ctx))
;
module.exports = notice;
Copy the code
The client
1. Download the socket. IO – client
yarn add socket.io-client -S
Copy the code
2. Create the web-socket.js tool method
import io from 'socket.io-client';
export default class WebSocket {
socket = null;
connect(url, path = '/socket.io') {
console.log('Connect socket');
this.socket = io(url, {path, reconnection: true, reconnectionDelay: 10000});
}
disconnect() {
if(this.socket ! = null){ console.log('Disconnect socket');
this.socket.disconnect();
this.socket.close();
this.socket = null;
}
}
register(channel, listener){
if(this.socket ! = null){ this.socket.on(channel, listener); }}};Copy the code
3. The blog system connects to the socket. IO service
import {noticeTypeList} from ".. /.. /.. /.. /conf";
import WebSocket from ".. /.. /.. /.. /lib/plugins/web-socket";
startWebSocketServer(userId) {
const webSocket = new WebSocket();
const {NODE_ENV, SOCKET_URL} = process.env;
webSocket.connect(`${SOCKET_URL}`, `${NODE_ENV === 'production' ? '/prod' : ''}/notice`);
webSocket.register('connect', ()=>{
console.log('Socket connected');
webSocket.socket.emit('joinNoticeRoom', userId);
WebLayout.createWebSocket(userId, webSocket);
});
webSocket.register('disconnect', ()=>{
console.log('Socket disconnected');
});
webSocket.register('error', (msg)=>{
console.log(msg);
});
webSocket.register('getNotice', data => {
const {sendName, content, title, type} = data;
this.props.getUnreadMessageList();
notification.open({
message: `${sendName}${noticeTypeList[type]}"${title}"`,
description: content,
});
});
}
componentDidMount() {
const {userInfo: {userId}} = this.props;
const token = localStorage.getItem('authorization');
const isLogin = userId && token;
isLogin && this.startWebSocketServer(userId);
}
componentWillReceiveProps = nextProps => {
const {userInfo: {userId}} = this.props;
const {userId: currentUserId} = nextProps.userInfo;
if(userId ! == currentUserId) {if (currentUserId) {
localStorage.getItem('authorization') && this.startWebSocketServer(currentUserId); }}};Copy the code
4. Front end effect
Special note: NGINX supports WebSocket by allowing tunneling between clients and back-end servers. In order for NGINX to send Upgrade requests from clients to back-end servers, the Upgrade and Connection headers must be explicitly set, as shown in the following example:
location /wsapp/ {
proxy_pass http://wsbackend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
Copy the code
www.nginx.com/blog/websoc…