我是 NodeJS/Express/Socket.IO 的新手,并且使用 Socket.IO 通信制作了一个简单的剪刀石头布应用程序(在客户端,我使用的是 AngularJS)。到目前为止,应用程序的那部分工作得很好。
但是,我开始使用 Redis 实现 session ,并且偶然发现了一些问题。因为我这样做是为了学习,所以我决定使用套接字来完成应用程序的一部分(玩剪刀石头布游戏的整个实时部分),而另一部分不需要真正的- 使用常规 REST 的时间组件(排行榜、查看其他人的个人资料等)。
我遇到的问题是 connect.sid cookie 从未在客户端设置。我做了一个简单的 checkSession REST 调用来测试 session 是否持续存在,但似乎没有。我在 checkSession 调用中还注意到 req.sessionID 总是给我一个全新的 sessionID。现在,我不确定我是否应该手动创建 connect.sid,还是 Node 应该自动处理?如果我应该这样做,我应该怎么做? “设置授权”回调也从不在握手对象中包含 connect.sid cookie。
此外,根据我在研究过程中读到的内容,在常规 REST (Express) 和 Socket.IO 之间共享 session 可能有点麻烦。这是我的代码(我关闭了整个剪刀石头布逻辑以确保这不是导致问题的原因)。
package.json:
{
"name": "RPSLS.Node",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.5.1",
"session": "0.1.0",
"socket.io": "0.9.16",
"redis": "0.10.2",
"connect-redis": "1.4.7"
}
}
app.js:
var express = require('express');
var parseCookie = express.cookieParser("megaultrasupersecret");
var http = require('http');
var path = require('path');
var io = require('socket.io');
var app = express();
var server = http.createServer(app);
var ioServer = io.listen(server);
var redis = require('redis');
var RedisStore = require('connect-redis')(express);
// Route dependencies
var sharedData = require('./shared/data')();
var routes = require('./routes');
// Enable CORS
var allowCrossDomain = function (req, res, next) {
res.header("Access-Control-Allow-Origin", "http://rpsls.local" || "http://localhost" || "http://127.0.0.1");
res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
res.header("Access-Control-Allow-Headers", "Content-Type");
next();
}
// All environments
app.set('port', process.env.PORT || 7331);
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser("megaultrasupersecret"));
app.use(express.session({ store: new RedisStore({ client: redis.createClient() }), key: "connect.sid", secret: "megaultrasupersecret", cookie: { maxAge: 24 * 60 * 60 * 1000 } }));
app.use(allowCrossDomain);
app.use(app.router);
ioServer.configure(function () {
ioServer.set('store', new io.RedisStore({
redisPub: redis.createClient(),
redisSub: redis.createClient(),
redisClient: redis.createClient()
}));
ioServer.set('authorization', function (handshakeData, callback) {
console.log(handshakeData.headers.cookie); // always returns undefined
parseCookie(handshakeData, null, function (err) {
// both always returns undefined
console.log(handshakeData.signedCookies['connect.sid']);
console.log(handshakeData.cookies['connect.sid']);
});
callback(null, true); // error first callback style
});
});
app.get("/", routes.index);
app.get("/checkSession", routes.checkSession);
ioServer.sockets.on('connection', function (socket) {
// ... socket logic ...
});
server.listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
checkSession 实现:
module.exports = function () {
return {
index: function (req, res) {
res.send("RPSLS.Node API is online.");
},
checkSession: function (req, res) {
console.log("----------- SESSION: ");
console.log(req.session);
console.log("----------- Session ID: " + req.sessionID); // always a brand new sessionID
console.log("----------- Session UserName: " + req.session.userName); // never gets persisted
console.log("----------- Connect.sid: " + req.cookies["connect.sid"]); // always undefined
console.log("----------- REQ cookies: ");
console.log(req.cookies); // sometimes outputs some _ga cookie (have no clue what it's for), but nothing else
req.session.userName = "someUserName";
req.session.save(function () {
res.send("TEST");
});
}
};
};
它的console.log输出:
----------- SESSION (this is what gets stored in redis):
{ cookie:
{ path: '/',
_expires: Mon May 26 2014 22:56:23 GMT+0200 (Central European Daylight Time),
originalMaxAge: 86400000,
httpOnly: true } }
----------- Session ID: 7KIjYzdqfyZFCjDDT4bE1P5a
----------- Session UserName: undefined
----------- Connect.sid: undefined
----------- REQ cookies: {}
Angular HTTP 调用:
this.checkSession = function () {
$http.get('http://localhost:7331/checkSession')
.success(function (userName) {
console.log(userName);
});
};
这里有一些来自 Redis 的 key ,用于确认它正在工作(我还在应用程序的其他部分成功地将一些其他数据保存到 Redis,但认为这与这里无关):
127.0.0.1:6379> keys *
sess:Fe8ND2riR4jQEtCEmhYKi4hS
sess:WGLNkth7HW2PtR2AG4noId8Q
sess:Ph0aUwRWEtawEWxIrqVQj3Us
sess:RzLVnaLV8BPZqUsjCCzV9RCn
sess:ZfmMcGUyFf957IsVc1gkbXKb
sess:6zdD3PStbx1EmFtHjoxmVGkr
sess:QNyHy4PUNE21fBrgmjiyjNkq
我在 DevTools 中注意到的另一件事是名为 connect.sid 的响应 cookie,其中包含 session ID 和哈希密码。此 session ID 始终是我在 checkSession 中获得的新 ID。我应该在客户端上手动设置它,还是开箱即用?
这是来自响应 header :
Set-Cookie:connect.sid=s%3AvMXrIBuaheA7ZBkxql51HQfO.67KqBFY4DVS4rQ50jv2B6bn4V6LeLMpdMxcpP6P%2FXIc;
Path=/; Expires=Mon, 26 May 2014 21:19:05 GMT; HttpOnly
我花了很多时间试图解决这个问题,但我对为什么这不起作用一无所知。一切都在本地主机上运行。我不理解和做错了什么,我错过了什么?
edit1: 根据 mscdex的请求,console.dir(req.headers) 输出以下内容:
{ host: 'localhost:7331',
'user-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0', accept: 'application/json, text/plain, */*',
'accept-language': 'en-US,en;q=0.5',
'accept-encoding': 'gzip, deflate',
dnt: '1',
referer: 'http://localhost:9000/',
origin: 'http://localhost:9000',
connection: 'keep-alive',
'if-none-match': '"-286616648"',
'cache-control': 'max-age=0' }
edit2: 如果它有任何重要性,NodeJS 应用程序正在 localhost:7331 上运行,我尝试在 上运行 AngularJS localhost:9000(通过 grunt)、127.0.0.1:9000 和 rpsls.local(通过 MS IIS)具有相同的结果。
最佳答案
尝试将 res.header("Access-Control-Allow-Credentials", "true"); 添加到您的 allowCrossDomain 中间件函数中。您也可以考虑使用 cors中间件,而不是自己处理 CORS。
然后修改您的 Angular 获取调用以将 withCredentials: true 添加到请求配置中:$http.get('http://localhost:7331/checkSession', { withCredentials: true }).
关于node.js - Connect.sid 始终未定义并且 req.session ID 不断重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23860202/
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我想学习一些关于Continuation的知识,使用callcc方法从一些文章中键入几个示例,但我遇到了错误:NoMethodError:undefinedmethod`callcc'formain:Objectfrom(pry):2:in`'没有文章提到包含延续库。那么如何解决这个问题呢?谢谢编辑:ruby1.9.2p290(2011-07-09修订版32553)[x86_64-linux] 最佳答案 您需要要求“继续”。require'continuation' 关于ruby-继续,
我正在开发我的第一个Rubygem,并捆绑了cucumber、rspec和shoulda-matches进行测试。当我运行rspec时,出现以下错误:/app/my_gem/spec/spec_helper.rb:6:in`':undefinedmethod`configure'forShoulda::Matchers:Module(NoMethodError)这是我的gem规范:#my_gem.gemspec...Gem::Specification.newdo|spec|......spec.add_development_dependency"activemodel"spec.a
有谁知道在Heroku的Bamboo堆栈上启动并运行使用DataMapper的Sinatra应用程序所需的魔法咒语?Bamboo堆栈不包含任何预安装的系统gem,无论我尝试使用何种gem组合,我都会不断收到此错误:undefinedmethod`auto_upgrade!'forDataMapper:Module(NoMethodError)这是我的.gems文件中的内容:sinatrapgdatamapperdo_postgresdm-postgres-adapter这些是我将应用程序推送到Heroku时安装的依赖项:----->Herokureceivingpush----->Si
我目前对后台队列不太满意。我正在尝试让Resque工作。我已经安装了redis和Resquegem。Redis正在运行。一个worker正在运行(rakeresque:workQUEUE=simple)。使用Web界面,我可以看到工作人员正在运行并等待工作。当我运行“rakeget_updates”时,作业已排队但失败了。我已经用defself.perform和defperform试过了。发条.raketask:get_updates=>:environmentdoResque.enqueue(GetUpdates)end类文件(app/workers/get_updates.rb)c
我正在为一个类赋值,它在rspec测试中使用了column_types方法。it"Userdatabasestructureinplace"doexpect(User.column_names).toinclude"password_digest","username"expect(User.column_types["username"].type).toeq:stringexpect(User.column_types["password_digest"].type).toeq:stringexpect(User.column_types["created_at"].type).t
我正在尝试循环哈希数组。当我到达获取枚举器开始循环的位置时,出现以下错误:undefinedmethod`[]'fornil:NilClass我的代码如下所示:defextraireAttributs(attributsParam)classeTrouvee=falsescanTrouve=falseownerOSTrouve=falseownerAppTrouve=falseresultat=Hash.new(0)attributs=Array(attributsParam)attributs.eachdo|attribut|#CRASHESHERE!!!typeAttribut=a
我最近开始从事一个项目,该项目使用git进行存储并使用ruby作为前端。我的脚本的第一个版本使用了ruby-git,虽然非常简单,但还不错。当我需要对我的提交和日志做更具体的工作时,建议我转向砂砾。然而,我在早期遇到了障碍——grit似乎无法克隆远程存储库。我发现使用Repository类的所有示例都创建了一个本地存储库并搜索了我发现Grit的clone方法未定义的源代码。给了什么?这是我的第一个StackOverflow问题,在此先感谢您的帮助。 最佳答案 由于Git结构良好,Grit使用缺少的方法(Grit::Git#m