第一张图证明对象的属性值是存在的
第二张图,对象属性为undefined
redis 取出来的是字符串吧,console.log(typeof result)
一下就知道了
@hyj1991 是string类型,如果session在redis里面只是string类型,那么我如何操作这个session,比如我在session添加一个计数器,count:n。如果获得这个n,string类型不知道怎么处理?希望指点一下
先将json字符串转换成json对象
let resultData = JSON.parse(result);
console.log(resultData.count);
LZ 这个错误很经典(我也犯过)
@foora 谢谢,多问一下,创建后的session,是否可以随意添加属性字段,可以通过什么方法? 现在使用的ioredis,和koa-session2,看了文档半天不知道如何添加给已经存在的session添加字段,属性
@chaoxihailing 这个创建后的session的确是可以添加你所需要的属性字段。
// session增加user字段
ctx.session.user = 'test1';
// session读取user字段
let user = ctx.session.user;
@foora session可以自由添加属性字段了,但是却没有同步到redis,redis里面的字段还是创建时的字段,怎么解决
// example.js 引用Strore.js
const Store = require("./Store.js");
app.use(session({
store: new Store(),
}));
router.post(’/signin’, async (ctx, next) => {
ctx.session = {
count: count,
name: “boy”
}
var
name = ctx.request.body.name || ‘’,
password = ctx.request.body.password || ‘’;
console.log(signin with name: ${name}, password: ${password}
);
if (name === ‘koa’ && password === ‘12345’) {
ctx.response.body = <h1>Welcome, ${name}!</h1>
;
} else {
ss.get(“failcountuser:1234”).then((result) => {
let resultData = JSON.parse(result);
console.log(resultData.count);
ctx.session.user = “test1”;
let user = ctx.session.user;
console.log(user);
console.log(resultData);
console.log(ctx.session);
})
// Store.js
const Redis = require("ioredis");
const { Store } = require("koa-session2");
class RedisStore extends Store {
constructor() {
super();
this.redis = new Redis({
port: 6379,
host: "127.0.0.1",
family: 4,
// password: "hhhh",
db: 0,
}
);
}
async get(sid) {
let data = await this.redis.get(`SESSION:${sid}`);
return JSON.parse(data);
}
async set(session, { sid = this.getID(24), maxAge = 1000000 } = {}) {
try {
// Use redis set EX to automatically drop expired sessions
// await this.redis.set(`SESSION:${sid}`, JSON.stringify(session), 'EX', maxAge / 1000);
await this.redis.set(`failcountuser:1234`, JSON.stringify(session), 'EX', maxAge / 10);
} catch (e) {}
return sid;
}
async destroy(sid) {
return await this.redis.del(`SESSION:${sid}`);
}
}
module.exports = RedisStore;
1.example.js里的/signin路由,每次请求这条路由,session就被重新设置了一遍。
ctx.session = {
count: count,
name: “boy”
}
2.重新设置了session后,当你跑到ss.get(“failcountuser:1234”)的时候,因为是个promise,异步的,还没等到结果返回,代码就直接继续往下执行。等到promise返回,你在promise的then里用ctx.session添加修改属性,这时候,请求已经结束了,因此不会同步到redis上。因为同步的步骤是在session中间件里做的,在promise还没执行then的时候已经被执行了,在中间件每次存的session就是你步骤1创建的。
3.你的store.js那个this.redis.set的第一个参数不用写死,跟get的一样,这样你只需要ctx.session操作就行了,不用自己去查redis
@foora 你的回答让我明白了我的错误,现在有个问题,如果我在session添加一个token(用来存放图片验证码),在成功验证登录后,我如何删除这个token字段,应该不能重新请求/sigin路由,重新设置session
@chaoxihailing 验证登录后ctx.session.token = null;
@foora ctx.session的操作只能在controller层做?因为到了service层,不会传入ctx这个字段了,可是问题又来了,一般验证都是在service层做的,登录失败统计应该也在service层写,service没有ctx怎办?
@chaoxihailing 调用service层的时候把ctx传到service层
这样做合适吗?
@foora 大神,请求你的帮助,现在的状况是这样的,如果操作session的语句中,有报错语句,那么session语句不会执行,注解后,可以执行了session操作了,代码如下:
@chaoxihailing koa-session2中间件内部逻辑
取session存于ctx.session
await next()
发现跟之间不同,同步到数据库
你现在的koa中间栈大概是这样的。 […,session…,login,…]。
// 当程序正常执行的时候
1.session中间件执行到next()
2.login执行
3.session中间件执行next()后面的代码
// 抛出错误时
1.session中间件执行到next()
2.login执行,这里抛出错误
3.被catch到,请求结束,触发错误处理事件。
所以抛出错误的时候,没有执行后面的代码,session自然是没有更新到数据库。
@foora 你可以try/catch这个错误,那么这个错误就不会往外抛,这样就不会中断后面的代码的执行
那怎么解决?
可是这个异常是要抛出去的,比如账户用户密码错误,这类的错误信息要抛给客户端
谢谢
@chaoxihailing 内部把错误捕获了,然后设置response的status和message。
@foora 有个ip是192.168.10.108,我本机的ip是192.168.10.124(服务器在上面跑),我用ip为192.168.10.108的访问,那么每一次点击都会生成新的sessionID,而我本机访问服务器却没有问题,这个是跨域的问题?
@chaoxihailing 你这么描述我也无法判断出具体原因。但是每次生成新的sessionid应该就是因为cookie上的sessionid没有传递到服务器端。 1.如果你是在108机器访问124机器服务下的页面,然后页面内发ajax到124机器,这就不是跨域的原因。这时候服务端设的cookie会被存在124的域下,下次请求124的时候也会带上这个124域下的cookie。 2.如果你是在108机器访问108机器自己的页面,然后页面内发ajax到124机器,这就是跨域原因。这时候cookie是会被存在108这个域。但是你请求的是124的域,这个请求不会带上108域的cookie,因此cookie的sessionid就没带到服务端
我应该是第一种情况,用108的机器,访问124机器服务下的页面,服务器是在124机器上的,但是每次登录失败,都会生成一个新的sessionID,而不是唯一一个sessionID
我发现如果用非本机的浏览器访问,那么服务器会生成sessionID给浏览器,但是在浏览器中sessionID却没有发现它储存了sessionID,这是什么导致的?
服务器返回了sessionId
浏览器中却没有保存
@chaoxihailing 你这个页面的域是http://192.168.10.107:4209,如果你的服务器不是这个地址,那么就是cookie跨域问题
@foora 服务器地址不是107,而是124,有什么解决方案么?
@chaoxihailing 端口号也是4209?协议,ip,端口号都要相同才不是跨域
@foora 本地服务器的端口号是8000,4209是我在本机上用别的ip来访问本机服务的端口,方便我个人操作
@foora 我好奇为什么浏览器的Cookies,它的域是http://192.168.10.107:4209, 这个域是我用另一个pc的请求ip地址,而不是192.168.10.124这个地址呢
@foora 我说一下我的理解,看看对不对。现在有个两个ip地址,分别是192.168.10.124:80, 另一个是192.168.10.107:4209, 服务器搭建在124的那个ip上。现在用192.168.10.107:4209去访问192.168.10.124:80, 浏览器出现的域名是192.168.10.107:4209,因为它和192.168.10.124:80不是同源的,所以就算是用cors实现跨源,但是session依旧遵循这同源策略,所以无论怎么设置都不成功。 来自阮一峰老师的博客,如果在服务器有域名的情况,api域名应该会为 http://api.example.com, 而浏览器的储存Cookies的域名应该为 http://example.com,然后再用cors设置跨源? 不知道这个想法对不。
@chaoxihailing 你现在浏览器访问的是107,然后发请求到124。在浏览器上,这就是跨域了,因为你浏览器的107和你发请求的124是不同源。所以在124上设置sessionid的cookie,由于跨域了,虽然响应头里有了set-cookie,但是浏览器不会帮你创建保存下来。
像你发的阮一峰老师的博客这样设置后,访问107时,浏览器就会允许创建124域的请求设置的cookie。但这个cookie是设置在124的域下,所以你在107上的cookie列表是看不到这个cookie的。但是当你再一次向124发送请求的时候,这个请求就会携带上124域下的cookie。即之前请求设置的sessionid的cookie
@foora 我有个问题,像阮一峰老师博客那样设置的话,是不是像这样的的设置,就可以了?
@chaoxihailing 服务端是这么设置就可以了,前端的ajax请求还需要设置withCredentials = true。
@foora 还是不行
@foora 还是会每次登录失败,创建一个新的sessionID
@foora 这个是不是意味在开发环境,解决不了跨域问题,必须有真实的域名
@foora 如果nginx代理,那么需要在nginx设置cors吗?