个人项目记录 -- VChat

7 篇文章 0 订阅

VChat - 一个通讯社交类WebApp,本文用于记录开发遇到的磕磕绊绊和技术点。

使用JWT(JSON WEB TOKEN)做接口权限设计

接口权限,即在客户端发送请求的时候,需要带上一个服务器给予的token,服务器根据该token判断该客户端是否可以获取资源或进行某些操作。

exm:
登陆成功时生成token给到客户端,客户端把token存在本地,每次请求时带上。

router.post('/signin',(req,res)=>{

  let pars = req.body,
      username = pars.username,
      password = pars.password,
      sql = $userSql.getByAccount;

  // 根据username 找出用户信息 利用uid生成token
  conn.query(sql,username,(err,result)=>{
    if(result[0]){
      let user  = result[0]
      if(user.upassword === password){
        let secret = 'i am a good man'; //密钥

        //设置token
        let token = jwt.sign({ user }, secret, { expiresIn:  60 * 60 * 1 });
        res.json({'result':'登陆成功','token':token,'uid':user.uid})
   
      }else{
        res.json({'result':'密码错误'})
      }
    }else{
      res.json({'result':'用户不存在'})
    }
  });
});

客户端发送请求,服务端验证token

router.get('/friends',(req,res)=>{

  	let token = req.query.token,
      secret = 'i am a good man',//密钥
      friSql = $friSql.getById,
      userSql = $userSql.getById;

   jwt.verify(token, secret, function (err, decode) {
    if (err) {  //  时间失效 或者 遇到伪造的token
      res.json({'info':err})
    } else {
        // decode中就含有我们用于生成token的信息,我用的是uid
        let user = decode.user;
        let uid = user.uid;
    }
   });
});

// 前端使用axios请求
this.$axios.get('/api/user/friends',{
	params:{
		token: window.localStorage.getItem('token')
	}
}).then(res=>{
		if(res.data['result']){
			this.friends = res.data['result']
		}
	})

使用Socket.io 做点对点通信

流程:

1.用户登陆成功后,与服务器发起socket连接。

2.服务器使用一个users对象来保存用户与socket之间的映射,每当socket断开,都要更新users。每次用户断开连接时,都要将users[uid] 置为 null。每次连接时再分配新的socketId。

let users = {
   uid1: socketId,
   uid2: socketId
}

3.在sender发送信息给receiver时,是利用receiver的uid去获取其socketId来发送,但如果receiver不在线,其socketId自然为null,这时候需要先让服务器保存sender发送的信息,在下一次receiver连接socketId时将这些信息发给receiver。

// 存放离线信息
let unline_data = [
    // uid2 为接收方
    uid2 : [
      {
        senderId :
        msg :
      },
      .......
    ]
];

每次客户端上线时检查有没有离线信息给该客户端的,有的话发送,并清空该客户端离线信息。

//  连接成功
let hisMsg = unline_data[conn_uid] ? unline_data[conn_uid]:'没有新消息';
let initMsg = {
  msg: `${conn_uid} 连接成功 给你分配的socketId为${users[conn_uid].id}`,
  hisMsg: hisMsg
};
socket.emit('receiveMsg',{
  msg: initMsg,
  code: 200
});

unline_data[conn_uid] = null; // 清空离线信息

完整代码

let users = {
  // 'uid':'socketId'
};

// 存放离线信息
let unline_data = [
  /*
    // uid2 为接收方
    uid2 : [
      {
        senderId :
        msg :
      },
      .......

    ]
  */
];

io.on('connection',function(socket) {

  // 存储连接用户的uid 和 socketId映射
  let conn_uid = socket.request._query.uid;
  users[conn_uid] = socket;


  //  连接成功
  let hisMsg = unline_data[conn_uid]? unline_data[conn_uid]:'没有新消息';
  let initMsg = {
    msg: `${conn_uid} 连接成功 给你分配的socketId为${users[conn_uid].id}`,
    hisMsg: hisMsg
  };
  socket.emit('receiveMsg',{
    msg: initMsg,
    code: 200
  });

  unline_data[conn_uid] = null; // 清空离线信息

  // 这里监听 disconnect,就可以知道谁断开连接了
   socket.on('disconnect', function () {
     Object.keys(users).forEach(k=>{
       if (users[k] && users[k]===socket){
         users[k] = false
       }
     });
      console.log('socket disconnect: ' + socket.id);

   });

  //接收数据 并转发给相应的用户 实现单点聊天
  socket.on('sendMsg', function (obj) {

      let uid = obj.uid;
      let uid2 = obj.uid2;
      let msg = obj.msg;

      let data = {
        senderId: uid,
        receiverId: uid2,
        msg: msg
      };

      // 接收方在线(socket连接中)
      if(users[uid2]){
        users[uid2].emit('receiveMsg',data);
      }else{
        // 对方不在线,用数据结构先纯起来
        if(! (Object.prototype.toString.call(unline_data[uid2]).slice(8,-1) === 'Array')){
          unline_data[uid2] = []
        }
        unline_data[uid2].push(data)
      }
  });
});

用Vuex管理Socket

router.beforeEach((to,from,next)=>{
	let uid = window.localStorage.getItem('uid');
    let socket = store.getters.getSocket;
    
    // store中没有 就重新连接 并提交到store中
    if (!socket){
        store.dispatch('setSocket',io.connect('//192.168.137.1:3000',{
            'force new connection': true,
             'query': {
                uid:uid
             }
          }));//与服务器进行连接
       //监听接收信息
       store.getters.getSocket.on("receiveMsg",function (data) {
           let msg = data.msg;
           console.log(msg);
       });
    }
    next() // 继续跳转路由
});

Vuex:

import Vue from 'vue'
import Vuex from 'vuex'
import io from 'socket.io-client'
Vue.use(Vuex)

const store = new Vuex.Store({
  state:{
    headTitle:'聊天',
    socket:null
  },
  getters: {
    getHeadTitle: function (state) {
      return state.headTitle;
    },
    getSocket:function(state){
      return state.socket
    }
  },
  mutations:{
    setHeadTitleFunc:function(state,title){
      state.headTitle = title;
    },
    setSocketFunc:function(state,socket){
      state.socket = socket
    }
  },
  actions:{
    setHeadTitle:function(context,title){
      context.commit('setHeadTitleFunc',title)
    },
    setSocket:function(context,socket){
      context.commit('setSocketFunc',socket)
    }
  }
});

export default store

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值