白嫖方案:微信 Access_token 时效 2 小时的管理问题

2020-08-05 12:47:38 +08:00
 Visitor233

项目:net core3.1, PostgreSQL12

注:目前没有考虑队列和 redis,定时任务这个没办法再说吧

如题,现在是把获取到的 token,直接存在 psql 库一个单独放各种 token 的表里。有 appid 、token 类型、过期时间(当前时间+2 小时-xx 分钟)、是否更新这四个关键字段。

目前我分了五种情况,代码不方便发,我文字描述吧。

前提:通过参数查到对应的 token 信息,没有就第一种情况处理,有则判断后面四种 一:库没有,申请到新的直接插表 二:库有,且请求在有效期内,直接返回 token 三:库有,但已经到了 xx 分钟时间段内且是否更新字段为 false,需要更新 token 。于是先将字段改为 true,直接 context.savechanges 。然后再申请新的 token,局部更新旧 token,并将字段改为 fasle,再 save,返回新 token 四:库有,也到了 xx 分钟,但是否更新为 true 。直接返回 token (注意:我想这里可能会有脏读,但没关系,微信说了,token 更新期间,旧 token 仍有 5 分钟有效期) 五:库有,但有效期已经过了 xx 分钟,需要更新,考虑到瞬时大量请求刚好赶上,我直接 lock 申请的函数,再更新 token 。

目前就这样,单一请求各个阶段都试了,没问题,但没做压测(我不会,下了 jmeter 没用过) 现在回想起来,我入行一年半还不会多线程很 low 啊,这种单一资源竞争还得写 5 个 if else,罪过罪过。 还请各位大佬在评论区指点一番,先在次谢谢各位。鞠躬.jpg

5043 次点击
所在节点    程序员
34 条回复
encro
2020-08-05 12:59:40 +08:00
$token = $cache->get($app_token_key);
if(!$token){
$token = $app->getToken();
$cache->set(app_token_key,$token,$expire-5*60);
}
return $token;
soulzz
2020-08-05 13:03:50 +08:00
这个用 java 来写就很方便,引入 guava
设定 key 两小时失效
没有 token 直接 callable 里调用申请新的
teawithlife
2020-08-05 14:39:34 +08:00
不知道微信对获取 token 的频率有没有什么限制,如果没有限制的话,单独开个进程,每隔 90 分钟刷一次 token,需要用到的时候直接用就行了
pagepancn
2020-08-05 15:00:28 +08:00
@teawithlife 获取 token 每个月是有次数上限的,不能这么干
useben
2020-08-05 15:23:37 +08:00
考虑到瞬时大量请求刚好赶上. token 不放缓存, 单纯 mysql 扛不住...
直接 token 存 redis, 过期时间设为将近 2 小时, 过期再去请求一个就行了. 期间所有应用共用. 均摊下来时间复杂度还是 O(1)
iyangyuan
2020-08-05 15:39:01 +08:00
根本就不需要入库,用 Java 的话,放内存,加一个读写锁就搞定了。如果是微服务项目,单独做一个接口
kanezeng
2020-08-05 16:00:55 +08:00
@pagepancn 单独一个进程 90 分钟刷一次不会碰到频率上限的(每天 2000 次),只不过存在一点小风险,就是当业务进程取到老 token 还没使用时,刷新线程刷新了 token 导致老 token 失效,这时候业务进程使用老 token 会失败。不过按微信的说法,新老 token 能同时有效 5 分钟,所以应该也没问题
dhssingle
2020-08-05 16:21:47 +08:00
简单问题复杂化,单体应用的话 MemoryCache 足够用了,甚至静态变量也不是不可以。
lovesky
2020-08-05 16:26:03 +08:00
@pagepancn 获取 access_token,每日限额 2000 次,90 分钟刷一次完全没问题。
huobazi
2020-08-05 16:33:11 +08:00
这个? 没看懂做什么用的啊? 或者, 为什么做这个呢?
sunmoon1983
2020-08-05 16:44:34 +08:00
redis 不行吗?
quan01994
2020-08-05 17:05:51 +08:00
MemoryCache
unnamedhao
2020-08-05 17:11:26 +08:00
其实为了保险还需要做一个检测,
比如不小心在其他地方(例如测试环境)申请了 token,会导致当前 token 失效。
所以需要在当前环境使用 token 调用接口时检测返回的错误码,
如果错误码是 token 错误,
则需要设置标志重新获取 token
tcfenix
2020-08-05 17:12:22 +08:00
不是很明白为什么把这么简单的事情搞得这么复杂,
拿到了 access token 直接放 redis,设置 2 小时超时

每次请求过来去 redis 找, 如果有的话,对比一下就过了,没有的话就说明过了两小时,重新去微信找咯

追求性能的话弄个一分钟之类的内存缓存不就好了....
你弄个数据库什么一堆架构真是何苦?
h82258652
2020-08-05 17:13:20 +08:00
不需要多线程。直接用 asynclock ( nito.asyncex 这个包)。反正把请求微信开始到写入存储包起来就行了。(内存存储、磁盘存储、数据库存储都行)
减 xx 分钟也不需要,一般这种会有 slide time 。
xcstream
2020-08-05 17:27:29 +08:00
定时请求 入库 结束了
Visitor233
2020-08-05 18:41:42 +08:00
很抱歉,一开始写的时候就想写这是个中台(学校、医院、还有个啥系统三个合一起的),访问量有点多,我不知道是什么概念,就定 100W 吧。但刚看了一遍,发现没写明这一点。
Visitor233
2020-08-05 18:46:26 +08:00
@tcfenix 抱歉,是我没写明白,项目想减少依赖,所以 redis 能不用就不用,但今天跟经理一看代码好像写的更麻烦了= =
chinvo
2020-08-05 18:55:32 +08:00
killergun
2020-08-05 19:03:17 +08:00
定时,每两个小时向微信申请一次,将 token 放到 redis,过期时间是两个小时+一分钟。用了很多年没什么问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/695799

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX