背景
小程序登录需要获取手机号,调用该接口发现接口报错并返回错误码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"));
}
}
标签:access,String,微信,secret,接口,40001,token,appId
From: https://www.cnblogs.com/hello-czf/p/17652243.html