在做項目時,需要實現消息提醒,因爲現在有多個項目,都需要實現。
爲了實現多項目公用,和以後項目也可以使用。
單獨開了個項目,起了個node 服務來實現消息提醒。
用express redis socket.io來實現的。
session 都存在redis裏,所有的服務都一樣。這樣實現了,sessio共享
只要其他項目登錄了,消息服務也就登錄了。
因爲要多個項目共用,所以會在項目中引用socket.io js 然後創建
var socket=io('http://localhost:8007');
鏈接到8007也就是消息服務器。
消息服務io connection 鏈接上後,通過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('http://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)
}
當然這種實現是有問題 的,並不是時時消息提醒。
而且當鏈接數大時不斷輪循會給服務器和帶寬帶來很大壓力。