核心提示:express redis socket 消息提醒方案:本地emit 轮循服务器获取redis 再推送在做项目时,需要实现消息提醒,因为现在有多个项目,都需要实现。为了实现多项目公用,和以后项目也可以...
express redis socket 消息提醒方案:本地emit 轮循服务器获取redis 再推送
在做项目时,需要实现消息提醒,因为现在有多个项目,都需要实现。
为了实现多项目公用,和以后项目也可以使用。
单独开了个项目,起了个node 服务来实现消息提醒。
用express redis socket.io来实现的。
session 都存在redis里,所有的服务都一样。这样实现了,sessio共享
只要其他项目登录了,消息服务也就登录了。
因为要多个项目共用,所以会在项目中引用socket.io js 然后创建
var socket=io('https://localhost:8007');
链接到8007也就是消息服务器。
消息服务ioconnection 链接上后,通过socket.request.headers.sookie 来获取请求的cookie 找到connect.sid 得到sid。
再从redis上查找对应的用户信息。保存到链接socket上。然后发送emit open ,表示链接成功。
本地接收到后轮循向服务器发请message 请求来获取消息。
服务器查询redis获取消息,并emit 返回。
以下是服务端代码:
/*star 2016-8-20 socket 从请求中获取cookie 也就是token 再从redis里取到token对应的user 信息。 这后向socket页面emit(open) 表示当前登录用户链接socket成功。 本地轮循发起emit message 事件,获取用户的提示条数。 服务器根据 userid 从redis里读取提示条数并返回。 ----此为node socket 消息服务器第一种解决方案 */ var express = require('express'); var path = require('path'); var cookieParser = require('cookie-parser'); var bodyParser = require('body-parser'); var session = require('express-session'); var RedisStore = require('connect-redis')(session); var http = require('http'); var redis_api=require('./redis_api.js') var port=8007; var app = express(); // view engine setup app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public'))); // 设置 Session app.use(session({ store: new RedisStore({ host: "127.0.0.1", port: 6379, db: 0 //pass: 'yu' }), resave:false, saveUninitialized:false, secret: 'keyboard cat' })) app.use(function(req,res,next){ console.log(req.url); next(); }) app.get('/socket',function(req,res){ res.header("Access-Control-Allow-Origin", "*"); //console.log(req.session.username) res.send(req.session) }) var server = http.createServer(app); server.listen(port); server.on('error', onError); server.on('listening', onListening); var io=require('socket.io')(server); var users=[] io.on('connection',function(socket){ console.log('open') //获取请求cookie var cookie_string=decodeURIComponent(socket.request.headers.cookie) //正则匹配 获取sid var s=/connect.sid=([^\.]+)/g.exec(cookie_string); var sid=''; if(s && s.length>1){ sid=s[1].split(':')[1]; //console.log(sid); var user; redis_api.getsid(sid,function(err,res){ if(!err){ user=res; socket.emit('open',{sid:sid,user:user.user}) socket.sid=sid; socket.user=user.user; //链接数测试 /*var n=9000000; while(n--){ users.push(socket); }*/ } }) } socket.on('message',function(res){ console.log(res); switch(res.action){ case "read": read(); break; } }) function read(){ redis_api.getmessage(socket.user.id,function(err,reply){ if(!err){ socket.emit('message',{type:1,action:'message',data:reply,number:users.length}) } }) } socket.on('disconnect',function(){ console.log('close') }) }) function onError(error) { if (error.syscall !== 'listen') { throw error; } var bind = typeof port === 'string' 'Pipe ' + port : 'Port ' + port; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': console.error(bind + ' requires elevated privileges'); break; case 'EADDRINUSE': console.error(bind + ' is already in use'); break; default: throw error; } } /** * Event listener for HTTP server "listening" event. */ function onListening() { console.log('localhost:'+port) }
以下是redis_api代码
var redis = require('redis'); var client = redis.createClient('6379', '127.0.0.1'); exports.getsid=function(sid,call){ //client.select('0',function(err){ //if(!err){ //console.log('select 0',err) client.get('sess:'+sid ,function(err,reply){ console.log('------sess:'+sid) console.log('sess:',sid,err,reply) console.log('end ------sess:'+sid) if(err){ call(err) }else{ //console.log('sess:'+sid+'=',reply) call(0,JSON.parse(reply)) } }) //} //}) } //根据userid 获取消息数 exports.getmessage=function(userid,call){ client.select('0',function(err){ if(!err){ client.get('message:'+userid,function(err,reply){ if(!err){ console.log('message:'+userid+'='+reply) call(0,JSON.parse(reply)) } // 关闭链接 //client.quit(); }) } }) }
以下是页面代码:
var socket=io('https://localhost:8007'); socket.on('open',function(res){ console.log('开了',res) time(); //socket.emit('message',{id:1,type:1,action:'read'}) }) socket.on('message',function(res){ console.log(res,new Date()); }) //以下为轮循发请emit 获取消息数 function time(){ setInterval(function(){ socket.emit('message',{type:1,action:'read'}) //socket.emit('message',{type:1,action:'read'}) },3000) }
当然这种实现是有问题 的,并不是时时消息提醒。
而且当链接数大时不断轮循会给服务器和带宽带来很大压力。