想获得promise返回对象的属性,但是只能有获得对象
发布于 7 年前 作者 chaoxihailing 7916 次浏览 来自 问答

QQ截图20170912150814.png 第一张图证明对象的属性值是存在的

QQ截图20170912151223.png 第二张图,对象属性为undefined

37 回复

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;

@chaoxihailing

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操作了,代码如下: image.png

@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 image.png

浏览器中却没有保存 QQ截图20170920103627.png

@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依旧遵循这同源策略,所以无论怎么设置都不成功。QQ截图20170920162617.png 来自阮一峰老师的博客,如果在服务器有域名的情况,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 我有个问题,像阮一峰老师博客那样设置的话,是不是像这样的的设置,就可以了? image.png

@chaoxihailing 服务端是这么设置就可以了,前端的ajax请求还需要设置withCredentials = true。

@foora 还是会每次登录失败,创建一个新的sessionID

@foora 这个是不是意味在开发环境,解决不了跨域问题,必须有真实的域名 image.png

@foora 如果nginx代理,那么需要在nginx设置cors吗? image.png

回到顶部