利用socket.io實現用戶實時聊天

聊天存入數據庫需要的參數標識:
	兩個用戶的標識
	聊天消息內容
	發送消息的時間
	當前對話消息的標識


1、在前臺的異步請求中,使用socket來發送消息
	向後臺發送時,應該將兩個用戶的標識傳遞,且能看出誰向誰發,還要攜帶聊天內容
	
2、在後臺中,使用socket來接收,不需要路由組件,寫成外部模塊來接收
		後臺收取到後存入數據庫中,並向客戶端返回存入的內容
			其中:因爲客戶端都是監聽的相同名稱,所以都能收到服務器返回的發送內容
			
3、在用戶登錄等時候,就向後臺發送請求,獲取消息列表
	通過當前對話消息的標識,確定當前對話的消息
	通過用戶的標識,確定誰發送
	通過消息的時間標識,確定誰先發送
	
4、實時同步每條消息
	消息發送後,後臺接收存入數據庫然後將發送的消息發揮前端,前端監聽接收後,將觸發方法使得消息列表增加該消息,如reducer中增加一個case,來使得消息列表增加

基於React的Redux模式下的代碼示例:
actions.js中異步方法使用socketio發送:

 function initIO(dispatch,userid)
 {
      if(!io.socket){
          io.socket=io('ws://localhost:4000')
          io.socket.on('receiveMsg', function (chatMsg) {
               console.log('瀏覽器端接收到消息:', chatMsg)
               //只有當前會話才分發action保存
               if(userid==chatMsg.from||userid==chatMsg.to)
               {
                    dispatch(receiveMsg(chatMsg))
               }
          })
      }
 
 }

 //異步發送消息
 export const sendMsg=({from,to,content})=>{
      return dispatch=>{
          initIO();
          console.log('瀏覽器發送消息',{from,to,content})
          io.socket.emit('sendMsg',{from,to,content})
      }
 }

後臺:

let express = require('express')
var bodyParser = require('body-parser');
var md5=require('blueimp-md5');
var cookieParser = require('cookie-parser');

var urlencodedParser = bodyParser.urlencoded({ extended: false });

const {UserModel,ChatModel} =require('./db/models');
const filter={password:0,__v:0};

var app=express();

//socket.io
var server = require('http').Server(app);
require('./socketio/test')(server);

server.listen(4000,function(){
    console.log('this express server is running at http://127.0.0.1:4000 ');
});

app.use(cookieParser());

...

引入的模塊:

const {ChatModel}=require('../db/models')

module.exports = function (server) {
    // 得到 IO 對象
    const io = require('socket.io')(server)

    //監視連接(當有一個客戶連接上時回調)
    io.on('connection', function (socket) {
        console.log('soketio connected')

        // 綁定 sendMsg 監聽, 接收客戶端發送的消息
        socket.on('sendMsg', function ({from,to,content}) {
        
            console.log('服務器接收客戶端發送',{from,to,content})
            //保存消息進數據庫,再將保存信息返回給前臺
            const chat_id=[from,to].sort().join('-');
            const create_time=Date.now();
            //存入數據庫
            new ChatModel({from,to,content,chat_id,create_time}).save(function(err,chatMsg){
                //向客戶端發送數據
                io.emit('receiveMsg',chatMsg);
            })
        })
    })
}

獲取消息列表:

//異步獲取消息函數
 async function getMsgList(dispatch,userid)
 {
     initIO(dispatch,userid);
     const response =await reqChatMsgList();
     const res=response.data

     if(res.code===0)
     {
          const{users,chatMsgs}=res.data
          dispatch(receiveMsgList({users,chatMsgs}))

     }
 }

前臺獲取到消息後,根據標識對消息的處理:

       const {user}=this.props
       const {users,chatMsgs}=this.props.chat
       
       //計算當前聊天的chatId
       const meId=user._id;
       if(!users[meId])
       {
           return null;
       }
       const targetId=this.props.match.params.userid;
       const chatId=[meId,targetId].sort().join('-');
	   
	   //獲取當前對話的所有消息
       const msgs=chatMsgs.filter(msg=>msg.chat_id==chatId)
       //頭像
       const targetHeader=users[targetId].header;

       const targetIcon=require(`../../assets/imgs/${targetHeader}.png`)
	   
	   return
           {
            msgs.map(msg=>{
                 if(meId===msg.to) //對方發給我的
                 {

                     return  <Item
                             key={msg._id}
                              thumb={targetIcon}
                             >
                                 {msg.content}
                             </Item>
                 }else{
                     return  <Item
                              key={msg._id}
                              className='chat-me'
                              extra='我'
                             >
                                 {msg.content}
                             </Item>
                 }
             })
         }

reducer:

//聊天狀態
const initChat={
    users:{},
    chatMsgs:[],
    unReadCount:0 //總未讀數量
}
function chat(state=initChat,action)
{
    switch(action.type)
    {
        case RECEIVE_MSG_LIST:
            const {users,chatMsgs}=action.data
            return {
                users,
                chatMsgs,
                unReadCount:0
            }
        case RECEIVE_MSG:
            const chatMsg=action.data
            return {
                users:state.users,
                chatMsgs:[...state.chatMsgs,chatMsg],
                unReadCount:0
            }
        default:
            return state
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章