微信小程序调用微信接口报40001

背景

小程序登录需要获取手机号,调用该接口发现接口报错并返回错误码40001。该错误码官方解释:获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口。排查发现reids里的token缓存并没有过期,后面想到dev、sit环境都用到了获取token的接口,发现调用该接口会使上一个token失效。由于dev、sit环境是隔离的,所以两个环境只要有使用都会调该接口,必然会导致某个环境token失效。

解决方案

参考文章
方案一:使用中控服务器,说白了就是共用一台服务器的redis来保存缓存。
方案二:增加容错机制,比如调用获取手机号的接口返回40001的时候删除缓存,再调用一次获取token的接口,获取新的token去调接口。
方案三:获取稳定版接口调用凭据,该接口可以调用不会产生新的token,就没有失效问题了。

工具类抽取

package com.sinocarbon.infinity.utils;

import com.alibaba.fastjson.JSON;
import com.sinocarbon.infinity.constant.SystemConstant;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @author czf
 * 对微信小程序服务端的api 二次封装
 */
@Slf4j
@Component
public class WxUtil {

    @Resource
    RedisUtil redisUtil;
    /**
     * 获取微信程序的token
     * @param appId appId
     * @param secret secret
     * @param type type 1:getTokenJsonObject 2:getStableATokenJsonObject
     * @return 获取微信程序的token
     */
    public  String getAccessToken(String appId,String secret,Integer type){
        Object o = redisUtil.get(SystemConstant.INFINITY_WX_ACCESS_TOKEN+appId);
        if (Objects.nonNull(o)){
            return String.valueOf(o);
        }
        JSONObject json;
        if (type == 1){
            json = getTokenJsonObject(appId, secret);
        }else {
            json =getStableATokenJsonObject(appId, secret,false);
        }

        String accessToken = String.valueOf(json.get("access_token"));
        String expiresIn = String.valueOf(json.get("expires_in"));
        log.info("获取微信小程序的token:+++++{}",accessToken);
        redisUtil.set(SystemConstant.INFINITY_WX_ACCESS_TOKEN+appId,accessToken, Long.parseLong(expiresIn));
        return accessToken;
    }


    /**
     * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getAccessToken.html
     * 获取微信程序的token 调用该方法需要增加容错机制
     * 获取access_token的请求次数是有限制的(一天2000次)
     * 公众平台存储层只会存储新老两个access_token,意味着假设开发者重复调用3次接口,则会导致最早的access_token立刻失效。
     * 所以dev、sit、prd三个环境使用,会导致某个环境token失效,一个环境老token实效性为5分钟。
     * 详情参考:https://developers.weixin.qq.com/community/develop/article/doc/000e0e0d52c4d88a0b2c583895b813
     * @param appId appId
     * @param secret secret
     * @return 获取微信程序的token
     */
    private static JSONObject getTokenJsonObject(String appId, String secret) {
        String requestUrl="https://api.weixin.qq.com/cgi-bin/token";
        //请求参数
        String params = "appid=" + appId + "&secret=" + secret + "&grant_type=client_credential";
        //发送请求
        String data = HttpUtil.get(requestUrl, params);
        //解析相应内容(转换成json对象)
        return JSONObject.fromObject(data);
    }

    /**
     * https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getStableAccessToken.html
     * 获取稳定版接口调用凭据
     * @param appId appId
     * @param secret secret
     * @param forceRefresh
     * force_refresh 默认使用 false。
     * 1. force_refresh = false 时为普通调用模式,access_token 有效期内重复调用该接口不会更新 access_token;
     * 2. 当force_refresh = true 时为强制刷新模式,会导致上次获取的 access_token 失效,并返回新的 access_token
     * @return 获取稳定版接口调用凭据
     */
    private static JSONObject getStableATokenJsonObject(String appId, String secret,boolean forceRefresh) {
        String requestUrl="https://api.weixin.qq.com/cgi-bin/stable_token";
        //请求体参数
        Map<String, Object> paramsMap = new HashMap<>();
        paramsMap.put("appid",appId);
        paramsMap.put("secret",secret);
        paramsMap.put("grant_type","client_credential");
        paramsMap.put("force_refresh",forceRefresh);
        //发送请求
        String data = HttpUtil.post(requestUrl, paramsMap);
        //解析相应内容(转换成json对象)
        return JSONObject.fromObject(data);
    }



    /**
     * 获取手机号
     * @param accessToken  accessToken
     * @param code code
     * @return 手机号
     */
    public String getPhoneNumber(String accessToken,String code){
        String requestUrl="https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token="+accessToken;
        //发送请求
        HashMap<String, Object> map = new HashMap<>(16);
        map.put("code",code);
        String data = HttpUtil.post(requestUrl, map);
        //解析相应内容(转换成json对象)
        JSONObject json = JSONObject.fromObject(data);
        log.info("getPhoneNumber()-----errCode:{}",json.get("errcode"));
        Object phoneInfo = json.get("phone_info");
        JSONObject phoneInfoJsonObject = JSONObject.fromObject(JSON.toJSONString(phoneInfo));
        return String.valueOf(phoneInfoJsonObject.get("purePhoneNumber"));
    }
}

posted @   C紫枫  阅读(2265)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示