我熟悉socket.io,我遇到了一个奇怪的问题。除非客户端刷新浏览器,否则服务器永远不会从客户端接收“连接”事件。
expressjs服务器很简单:
// server_app.js =========================
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http)
var socketJwt = require('socketio-jwt');
app.use(express.static(__dirname + '/public'));
....
io.use(socketJwt.authorize({
secret: 'secret',
handshake: true
}));
io.on('connection', function(socket) {
console.log('connection created');
socket.on("user logged in" function(data) {
console.log('user logged in');
// Do stuff with data
});
});
http.listen(3000, function() {
console.log('Express app started');
});
客户端使用AngularJS:
// angular_app.js ===========================
var app = angular.module('app', ['ServiceMOdule', 'ngRoute', 'ControllerModule']);
var service_mod = angular.module('ServiceModule', []);
var controller_mod = angular.module('ControllerModule', []);
...
我的angularjs模块:
// ServiceModule.js =============================
service_mod.factory('FooService',
function($http) {
return {
// Save token
save: function(){ .... )},
// Get token
getToken: function(){ .... },
// Login POST
login: function(email, password) {
return $http.post("/user/login", {"email": email, "password": password});
}
}
}
});
service_mod.factory('socketService',
function($rootScope, FooService) {
var token = FooService.getToken();
var socket = io.connect('http://localhost:3000', {'query': 'token=' + token });
console.log('servicesocket called');
return {
on: function(eventName, callback) {
socket.on(eventName, function() {
var args = arguments;
$rootScope.$apply(function() {
callback.apply(socket, args);
});
});
},
emit: function(eventName, data, callback) {
// Print out the event name to see if this was fired!
console.log(eventName);
socket.emit(eventName, data, function() {
var args = arguments;
$rootScope.$apply(function() {
if (callback) {
callback.apply(socket, args);
}
});
});
}
}
});
// ControllerModule.js =====================================
controller_mod.controller('LoginCtrl', ['$scope', 'FooService', 'socketService', function($scope, FooService, socketService) {
$scope.login = function(email, password) {
FooService.login(email, password).success(function(data) {
FooService.save(data['token']);
socketService.emit('user logged in', {'token': data['token']});
});
}
}]);
当用户点击登录按钮时,angularjs会触发LoginCtrl.login()
,保存从登录POST返回的令牌,然后继续执行emit()
通知socket.io用户已登录从Firebug中的控制台输出,我可以看到打印出事件user logged in
。在客户端,一切似乎都在膨胀。
问题是,服务器永远不会触发任何socket.io侦听器。 io.on('connection', function(socket){...});
永远不会打印connection created
。此外,尽管客户端在登录后调用user logged in
,但emit()
也永远不会被触发。
但是!如果我重新加载浏览器页面,connection created
将打印出来,但user logged in
仍未被触发,因为此时用户已登录。登录后立即浏览器刷新后,其他侦听器(此处未显示)也会触发。
为什么会发生这种情况?如何解决?