w7corp / easywechat

📦 一个 PHP 微信 SDK
https://easywechat.com
MIT License
10.26k stars 2.41k forks source link

第三方平台 多服务器,共用redis,报No component_verify_ticket found.问题 #2796

Closed 596868636 closed 5 months ago

596868636 commented 5 months ago

我用的环境

问题及现象

现有开放平台类:OpenPlatformService,把redis设置为默认缓存。

`public function __construct() { $this->config = config('wechat.open_platform'); $this->open_platform = new Application($this->config); //支付回调数据接收到的问题处理 if(!empty(request())){ $symfony_request = new SymfonyRequest(request()->get(), request()->post(), [], request()->cookie(), [], [], request()->rawBody()); $symfony_request->headers = new HeaderBag(request()->header()); $this->open_platform->setRequestFromSymfonyRequest($symfony_request); }

    //切换缓冲到redis,用于负载均衡
    $this->redis = Redis::connection('default')->client();
    $this->open_platform->setCache(new Psr16Cache(new RedisAdapter($this->redis)));
}`

现有两台服务器,一台共用的redis服务器: A服务器,第三方平台回调指向的是这台服务器,使用正常。 在redis服务器中,可以查询到component_access_token,的确有保存,格式为二进制格式。 image

在B服务器,使用和A相同代码和配置,调用相关接口,报:No component_verify_ticket found.

一开始以为是缓存没有指向同一个或者配置错误问题,但实际写代码测试,发现并不是,而是序列化可能导致的问题,请教下,是哪里问题?

image 如上图,因为跟踪代码到EasyWeChat\OpenPlatform\ComponentAccessToken 的 `public function getToken(): string {

    $token = $this->cache->get($this->getKey());
    if ((bool) $token && \is_string($token)) {
        return $token;
    }

    return $this->refresh();
}`

发现是$token取不到,所以有了上面的测试,同时refresh() 方法中,发现$this->verifyTicket->getTicket()也取不到,所以报了No component_verify_ticket found.

同时发现,A、B服务器互换, B服务器保存的内容是: s:95:"ticket@@@uPNSDPLB6yMe4JJGCVW7TlS-E1Xcp7Ldn0c4UuLoelQqbYnKovIoVO85SlD0Rwtpe4axoEn"; 这样的系列化结果, 而A服务器上保存的是: 上图乱码的结果,想着是哪里编码错误了?

596868636 commented 5 months ago

不好意思,应该是环境扩展上的问题,phpredis扩展的默认系列化格式不一致导致的,正常编排的话应该不存在这个问题,所以避免类似的环境出行,目前建议在代码配置中,强制设置redis 的 系列化方式进处理,避免不同的环境下导致的异常问题,相类似的案例供参考

596868636 commented 5 months ago

补充下,也要注意 intl扩展