Javen205 / TNWX

TNWX: TypeScript + Node.js + WeiXin 微信系开发脚手架,支持微信公众号、微信支付、微信小游戏、微信小程序、企业微信/企业号。最最最重要的是能快速的集成至任何 Node.js 框架(Express、Nest、Egg、Koa 等)
Apache License 2.0
635 stars 96 forks source link

多账号accesstoken是否存在错乱问题 #11

Open GavinSun09 opened 4 years ago

GavinSun09 commented 4 years ago

问题描述

我查看了一下所有接口的发送逻辑,先从缓存获取accesstoken

let accessToken: AccessToken = await OpenCpAccessTokenApi.getAccessToken(AccessTokenType.SUITE_TOKEN)

当多个服务号或企业号时,我们调用接口时需要先设置当前的appId并存入缓存ApiConfigKit.setCurrentAppId(appId) 然后去调用接口,上面代码获取到的token是根据缓存中当前的appId去取token,但是如果多个人同时操作,因为是异步操作,可能存在我发送请求时,当前的appId已经发生变化,获取到的token已经不是我这个appid所对应的token

Javen205 commented 4 years ago

你有好的解决方案吗?一起讨论一下

GavinSun09 commented 4 years ago

我这边根据目前的结构想到的是2种。

  1. 把appid 当作变量传进每一个接口方法里,通过appid 去缓存里获取相关的accesstoken,但是这种方式改动起来的工作量会比较大。

  2. 还有一种我想到的是,再调用接口方法前去维护一下accesstoken, 获取accesstoken或者判断是否过期去刷新token,然后当token确定有效时,调用接口前再 ApiConfigKit.setCurrentAppId(appId)设置token,但是在接口里面,使用同步的方式去 getAccessToken,这样因为node 的单线程,只要中间没有异步,应该就不会发生错乱的现象。

这两个仅仅是我目前的想法,也希望能有更多的好的处理方法。

Javen205 commented 4 years ago

之前就是使用的第二种方案,但有同学反馈 getAccessToken setAccessToken 建议设置为异步后面就改了,调用接口获取时加了 await 相当于也是同步。node 单线程,目前测试还没有发现错乱的问题。 如果还有问题请继续反馈。

zjsxfly commented 3 years ago

是不是apiConfig的kit和accesstoken的获取做成扩展或插件更好,由使用者自己维护逻辑,官方的作为默认,现在的话如果有自己逻辑得修改源代码

heibai01 commented 2 years ago

@Javen205 你好,ApiConfigKit 是否开放给使用者自己new呢,这样小程序、公众号等多应用开发时可以根据不同的kit进行调用。而不是在调用api前先ApiConfigKit.setCurrentAppId(appId)

cmzz commented 1 year ago

这个都是静态方法调用,在多应用模式下会存在问题

magicxie commented 12 months ago

野方法,把currentAppId的存储从全局偷换到异步上下文

以QyApiConfigKit为例,服务启动前调用下

import { QyApiConfigKit } from 'tnwx';
import { AsyncLocalStorage } from 'node:async_hooks';

const enhanceAsyncStorage = () => {
  const asyncLocalStorage = new AsyncLocalStorage();

  QyApiConfigKit.setCurrentAppId = (appId, corpId) => {
    const currentAppId = appId.concat(QyApiConfigKit.SEPARATOR).concat(corpId);
    const store = { currentAppId: currentAppId };
    asyncLocalStorage.enterWith(store);
  };

  QyApiConfigKit.removeCurrentAppId = () => {
    asyncLocalStorage.getStore()['currentAppId'] = '';
  };

  Object.defineProperty(QyApiConfigKit, 'currentAppId', {
    get() {
      return asyncLocalStorage.getStore()['currentAppId'];
    },
  });
};