preface
The project started because the work required a chat room function, but for some reason ended up using strophe.js based on XMPP protocol. I decided to make a cameo with Node, which was intended to be a simple one for the cameo chat page, but wasn’t satisfied with it, so had a recurring reconfiguration (seems to understand why the product manager changed the appearance to δΉβ‘δΉ danjun).
Many things, such as mongodb, I am also the first time to use, only mysql before. Therefore, I learned to write at the same time. In my spare time, I wrote intermittently for several months, including a whole set of front and back end interactions. UI is in accordance with their own feelings, no design talent (words to switch to the theme is still only a set of theme, it is not good design ~), light spray –. There are still many areas to be optimized and perfected in the project. Welcome to mention issues (q group at the end of the article, welcome to study and exchange with us).
Without further ado, this paper mainly talks about the design process of the project, as well as some functional ideas. Interested in the project students please go to the source code Vchat – from head to toe, an online chat web application (vue + Node + mongodb).
This is the dividing line — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — the night code word, it is cold recently
The project architecture
Technology stack
The front end mainly uses vUE bucket, not much to say, scaffolding construction project, VUEX state management, VUE-Router control routing, AXIos front and back end interaction. The back-end is a Node based service using Express. Why don’t I use KOA? It’s purely for convenience, because KOA is not familiar. Of course, the most important part of chat is communication. The project uses socket. IO to communicate with the front and back ends.
The database is mongoDB, including users, friends, group chats, messages, expressions, number pools and so on.
Functions overview
Functional design
Log in to register
During user registration in Vchat, a code number is randomly assigned. The code number is obtained from a pre-generated number pool (a number pool exists in mongodb). The number segment 10000001-10001999 is the user code, and the number segment 100001-100999 is the group chat code. Users can log in by code or account number.
// Number pool design* code Number * status1Has been used0* type is not used1The user2Group chat * random Random number index, used to randomly search for a certain item// user main field of the table* Name Account * pass password * Avatar avatar * Signature signature * nickname * Email * phone phone * sex gender * bubble * projectTheme * wallpaper * signUpTime registration time * lastLoginTime lastLoginTime * chatColor * province * city * town * ConversationsList Session list * Cover Cover listCopy the code
During registration, you need to check whether the account already exists, mark the randomly obtained code as used in the number pool, and encrypt the user password with MD5.
// Md5 password encryption
const md5 = pass= > { // Avoid multiple attempts to invoke MD5
let md5 = crypto.createHash('md5');
return md5.update(pass).digest("hex");
};
Copy the code
Login also needs to determine whether the user is registered, and supports account and code login.
const login = (params, callback) = > { / / login
baseList.users
.find({ // We can use $or directly to represent or relationships in mongodb
$or: [{"name": params.name}, {"code": params.name}]
})
.then(r= > {
if (r.length) {
let pass = md5(params.pass);
if (r[0] ['pass'] === pass) {
Date.now() is required!! ;
baseList.users.update({name: params.name}, {lastLoginTime: Date.now()}).then(raw= > {
console.log(raw);
});
callback({code: 0.data: {name: r[0].name, photo: r[0].photo}});
} else {
callback({code: - 1}); }}else {
callback({code: - 1}); }})};Copy the code
Login Permission Management
- The backend sets up the global middleware, and uniformly returns status: 0 for API requests that are not logged in
app.use('/v*', (req, res, next) => {
if (req.session.login) {
next();
} else {
if (req.originalUrl === '/v/user/login' || req.originalUrl === '/v/user/signUp') {
next();
} else {
res.json({
status: 0}); }}});Copy the code
- The front-end uses AXIOS to set up interceptors uniformly
// The HTTP Response server responds to the interceptor, which intercepts the no-login and 401 errors and jumps back onto the page to retrieve the token
instance.interceptors.response.use(
response= > { // Intercept failed login
if (response.data.status === 0) {
router.replace('/');
}
return response;
},
error => {
if (error.response) {
switch (error.response.status) {
case 401:
// Write the code to clear the token
router.replace('/'); }}return Promise.reject(error.response.data)
});
Copy the code
The message
In Vchat, message types include friend or group application, reply application (agree or reject), group notification, and chat message (text, picture, facial expression, and file).
Before implementing message sending, you need to have a general understanding of some socket. IO apis. See socket.io for detailed API documentation
// All message requests are made on a connected basis
io.on('connect', onConnect);
// Send to the current client
socket.emit('hello'.'can you hear me? '.1.2.'abc');
// To all clients except the sender
socket.broadcast.emit('broadcast'.'hello friends! ');
// to all clients in the same 'game' room except the sender
socket.to('game').emit('nice game'."let's play a game");
// to all clients in the same 'game' room, including the sender
io.in('game').emit('big-announcement'.'the game will start soon');
Copy the code
- To join the room
Join the room in the session list. The session list is automatically added when a friend application or group is successfully added. However, you can manually remove or add the removed session, and you will no longer receive messages from the removed session (similar to masking).
// The front end initiates a request to join the room
this.conversationsList.forEach(v= > {
let val = {
name: this.user.name,
time: utils.formatTime(new Date()),
avatar: this.user.photo,
roomid: v.id
};
this.$socket.emit('join', val);
});
// After receiving the request, the back end performs the join operation, records the members added in each room, and replies to inform the designated room that the members are online
socket.on('join', (val) => {
socket.join(val.roomid, () => {
if (OnlineUser[val.name]) {
return;
}
OnlineUser[val.name] = socket.id;
io.in(val.roomid).emit('joined', OnlineUser); // Include the sender
});
});
Copy the code
- A problem occurs when multiple rooms join multiple chat rooms at the same time. The socket can join multiple rooms and send messages to the specified room, but receives messages without distinguishing between rooms. In other words, messages from all rooms are sent to the client together. So we need to distinguish which messages belong to which rooms and distribute them ourselves. This requires a room ID to filter, which Vchat uses.
mes(r) { // Only messages from this room are displayed
if (r.roomid === this.currSation.id) {
this.chatList.push(Object.assign({}, r, {type: 'other'})); }}Copy the code
- Send a message
/ / the front-end send (params,type = 'mess') {// Send a messageif(! this.message && ! params) {return;
}
let val = {
name: this.user.name,
mes: this.message,
time: utils.formatTime(new Date()),
avatar: this.user.photo,
nickname: this.user.nickname,
read: [this.user.name],
roomid: this.currSation.id,
style: 'mess',
userM: this.user.id
};
this.chatList.push(Object.assign({},val,{type: 'mine'})); // Update view this.$socket.emit('mes', val);
this.message = ' '; } // The backend receives the message, stores it in the database, and forwards it to other members of the room, excluding the sender. socket.on('mes', (val) => {// Chat message apilist.savemessage (val); socket.to(val.roomid).emit('mes', val);
});
Copy the code
- Message Record All messages are stored in mongodb and history messages are retrieved when switching rooms. While in the current room, the latest messages are only appended to the DOM, not fetched from the database. By default, the chat window displays only the latest 100 messages. You can view more messages in the chat history.
// The front-end gets the history message of the specified room
this.$socket.emit('getHistoryMessages', {roomid: v.id, offset: 1.limit: 100});
// Back end associated table, paging, sorting
messages.find({roomid: params.roomid})
.populate({path: 'userM'.select: 'signature photo nickname'}) // Associate basic user information
.sort({'time': - 1})
.skip((params.offset - 1) * params.limit)
.limit(params.limit)
.then(r= > {
r.forEach(v= > { // Prevent information from not being updated after the user modifies the information
if(v.userM) { v.nickname = v.userM.nickname; v.photo = v.userM.photo; v.signature = v.userM.signature; }}); r.reverse(); callback({code: 0.data: r, count: count});
}).catch(err= > {
console.log(err);
callback({code: - 1});
});
Copy the code
Projects show
The home page
Chat window, can drag or zoom, chat wallpaper and text color Settings.
Personal Settings
Application of space
reading
- Basic introduction to Mongoose
- Socket. IO document
- Vchat topic switch implementation scheme comes from D2-admin
Communication group
Qq front-end communication group: 960807765, welcome all kinds of technical exchanges, looking forward to your joining
The public,
Welcome to pay attention to the public number front end engine, Jiang SAN crazy front two or three things, focus on technology, will often be confused. I hope to grow up with you in the future.
Afterword.
This paper mainly describes the overall design of Vchat and the realization of some main functions. In fact, there are many problems in the process of writing the project, such as Mongoose linkage query, file upload and so on. I won’t go into details here, but I will update it later. If Vchat helps you, remember to star.
- The article warehouse πΉ π° fe – code