在《Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明》中,我介绍了获取Accesstoken(通用接口)的方法。
在实际的开发过程中,所有的高级接口都需要提供Accesstoken,因此我们每次在调用高级接口之前,都需要执行一次获取Accesstoken的方法,例如:
或者当你对appId和appSecret进行过全局注册之后,也可以这样做:
然后使用这个accesstoken输入到高级接口的方法中,例如我们可以这样获取菜单:
var result = CommonApi.GetMenu(accesstoken);
通常情况下,这已经是一个很简洁的API调用过程。但是我们不愿意就这样停止,我们准备把几乎所有的API调用都缩短到一行。
这么做的同时,除了让代码更加简便,我们还有两个愿望:
- 让API可以自动处理已经变更的Accesstoken(在负载均衡等多个服务器同时操作同一个微信公众号的情况下,可能出现Accesstoken在外部被刷新,导致本机Accesstoken失效的情况),并且重新获取、返回最终正确的API结果。
- 不改变目前API调用的方式,完全向下兼容。
修改之后,我们可以直接这样一行调用API,每次只需要提供一个appId:
var result = CommonApi.GetMenu(appId);
当前在执行之前,我们需要像以前一样全局注册一下appId和appSecret:
可以看到,原先的accesstoken换成了appId(新版本仍然支持输入accesstoken),省去了获取accesstoken的过程。具体的过程见下文说明。
@H_404_30@ @H_404_30@SDK源代码实现过程之前为了实现自动处理(预料外的)过期的Accesstoken,SDK已经提供了Senparc.Weixin.MP/AccesstokenHandlerWapper.Do()方法。这次升级将AccesstokenHandlerWapper.cs重命名为ApiHandlerWapper.cs,废除Do()方法,添加TryCommonApi()方法,代码如下:
namespace Senparc.Weixin.MP
{
/// <summary>
/// 针对Accesstoken无效或过期的自动处理类
/// </summary>
public static class ApiHandlerWapper
{
/// <summary>
/// 使用Accesstoken进行操作时,如果遇到Accesstoken错误的情况,重新获取Accesstoken一次,并重试。
/// 使用此方法之前必须使用AccesstokenContainer.Register(_appId,_appSecret);或JsApiTicketContainer.Register(_appId,_appSecret);方法对账号信息进行过注册,否则会出错。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="fun"></param>
/// <param name="accesstokenOrappid">Accesstoken或AppId。如果为null,则自动取已经注册的第一个appId/appSecret来信息获取Accesstoken。</param>
/// <param name="retryIfFaild">请保留默认值true,不用输入。</param>
/// <returns></returns>
public static T TryCommonApi<T>(Func<string,T> fun,string accesstokenOrappid = null,bool retryIfFaild = true) where T : WxJsonResult
{
string appId = null;
string accesstoken = null;
if (accesstokenOrappid == null)
{
appId = AccesstokenContainer.GetFirstOrDefaultAppId();
if (appId == null)
{
throw new WeixinException("尚无已经注册的AppId,请先使用AccesstokenContainer.Register完成注册(全局执行一次即可)!");
}
}
else if (ApiUtility.IsAppId(accesstokenOrappid))
{
if (!AccesstokenContainer.CheckRegistered(accesstokenOrappid))
{
throw new WeixinException("此appId尚未注册,请先使用AccesstokenContainer.Register完成注册(全局执行一次即可)!");
}
appId = accesstokenOrappid;
}
else
{
//accesstoken
accesstoken = accesstokenOrappid;
}
T result = null;
try
{
if (accesstoken == null)
{
var accesstokenResult = AccesstokenContainer.GetAccesstokenResult(appId,false);
accesstoken = accesstokenResult.access_token;
}
result = fun(accesstoken);
}
catch (ErrorjsonResultException ex)
{
if (!retryIfFaild
&& appId != null
&& ex.JsonResult.errcode == ReturnCode.获取access_token时AppSecret错误或者access_token无效)
{
//尝试重新验证
var accesstokenResult = AccesstokenContainer.GetAccesstokenResult(appId,true);
accesstoken = accesstokenResult.access_token;
result = TryCommonApi(fun,appId,false);
}
}
return result;
}
}
}
对应API的源代码原来是这样的:
/// <summary>
/// 获取当前菜单,如果菜单不存在,将返回null
/// </summary>
/// <param name="accesstoken"></param>
/// <returns></returns>
public static GetMenuResult GetMenu(string accesstoken)
{
var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}",accesstoken);
var jsonString = HttpUtility.RequestUtility.HttpGet(url,Encoding.UTF8);
//var finalResult = GetMenuFromJson(jsonString);
GetMenuResult finalResult;
JavaScriptSerializer js = new JavaScriptSerializer();
try
{
var jsonResult = js.Deserialize<GetMenuResultFull>(jsonString);
if (jsonResult.menu == null || jsonResult.menu.button.Count == 0)
{
throw new WeixinException(jsonResult.errmsg);
}
finalResult = GetMenuFromJsonResult(jsonResult);
}
catch (WeixinException ex)
{
finalResult = null;
}
return finalResult;
}
现在使用TryCommonApi()方法之后:
/// <summary>
/// 获取当前菜单,如果菜单不存在,将返回null
/// </summary>
/// <param name="accesstokenOrappid">Accesstoken或AppId。当为AppId时,如果Accesstoken错误将自动获取一次。当为null时,获取当前注册的第一个AppId。</param>
/// <returns></returns>
public static GetMenuResult GetMenu(string accesstokenOrappid)
{
return ApiHandlerWapper.TryCommonApi(accesstoken =>
{
var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/get?access_token={0}",accesstoken);
var jsonString = HttpUtility.RequestUtility.HttpGet(url,Encoding.UTF8);
//var finalResult = GetMenuFromJson(jsonString);
GetMenuResult finalResult;
JavaScriptSerializer js = new JavaScriptSerializer();
try
{
var jsonResult = js.Deserialize<GetMenuResultFull>(jsonString);
if (jsonResult.menu == null || jsonResult.menu.button.Count == 0)
{
throw new WeixinException(jsonResult.errmsg);
}
finalResult = GetMenuFromJsonResult(jsonResult);
}
catch (WeixinException ex)
{
finalResult = null;
}
return finalResult;
},accesstokenOrappid);
}
我们可以观察到有这样几处变化:
1. 原先的accesstoken变量名称改为了accesstokenOrappid(新版本中所有相关接口都将如此变化)。
修改之后,这个参数可以输入accesstoken(向下兼容),也可以输入appId(无需再获取accesstoken),SDK会根据字符串长度自动判断属于哪种类型的参数。提供的参数有3种可能:
a) appId。使用appId需要事先对appId和appSecret进行全局注册(上文已说过),当调用API的过程中发现缓存的Accesstoken过期时,SDK会自动刷新Accesstoken,并重新尝试一次API请求,确保返回正确的结果。如果appId没有被注册过,会抛出异常。
b) accesstoken。这种情况下将使用原始的请求方式,如果accesstoken无效,将直接抛出异常,不会重试。
c) null。当accesstokenOrappid参数为null时,SDK会自动获取全局注册的第一个appId。如果某个应用只针对一个确定的微信号开发,可以使用这种方法。当全局没有注册任何appId时,将抛出异常。
2. 原方法内的访问API的代码没有做任何修改,只是被嵌套到了return ApiHandlerWapper.TryCommonApi(accesstoken =>{...},accesstokenOrappid)的方法中,以委托的形式出现,目的是为了在第一次可能的请求失败之后,SDK可以自动执行一次一模一样的代码。
此功能已经在Senparc.Weixin.MP v12.1中发布。
系列教程索引
地址:http://www.cnblogs.com/szw/archive/2013/05/14/weixin-course-index.html
- Senparc.Weixin.MP SDK 微信公众平台开发教程(一):微信公众平台注册
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二):成为开发者
- Senparc.Weixin.MP SDK 微信公众平台开发教程(三):微信公众平台开发验证
- Senparc.Weixin.MP SDK 微信公众平台开发教程(四):Hello World
- Senparc.Weixin.MP SDK 微信公众平台开发教程(五):使用Senparc.Weixin.MP SDK
- Senparc.Weixin.MP SDK 微信公众平台开发教程(六):了解MessageHandler
- Senparc.Weixin.MP SDK 微信公众平台开发教程(七):解决用户上下文(Session)问题
- Senparc.Weixin.MP SDK 微信公众平台开发教程(八):通用接口说明
- Senparc.Weixin.MP SDK 微信公众平台开发教程(九):自定义菜单接口说明
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十):多客服接口说明
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十一):高级接口说明
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十二):OAuth2.0说明
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十三):地图相关接口说明
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十四):请求消息去重
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十五):消息加密
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十六):AccessToken自动管理机制
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十七):个性化菜单接口说明
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十八):Web代理功能
- Senparc.Weixin.MP SDK 微信公众平台开发教程(十九):MessageHandler 的未知类型消息处理
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二十):使用菜单消息功能
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二十一):在小程序中使用 WebSocket (.NET Core)
- Senparc.Weixin.MP SDK 微信公众平台开发教程(二十二):如何安装 Nuget(dll) 后使用项目源代码调试
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。