介绍公众号的接入开发以及相关背景知识,包括公众号管理模式,开发配置,测试环境搭建,接入检验以及获取access_token等。
描述公众号开发接入的内容项。
在开发的过程中,我们会经常使用到微信公众号提供给开发者的微信官方开发文档,也可以参考其他开发帮助文档:WxJava - 微信开发 Java SDK(开发工具包)
其他开发常用连接:
- 测试公众号:测试公众号
- 微信公众平台接口调试工具:微信公众平台接口调试工具
1.公众号管理模式
即公众号的内容录入以及后台运营方式。
模式说明
微信公众平台提供了两种管理模式给我们,应该根据我们的需求来选择使用不同的模式。
- 编辑模式
主要针对非编程人员及信息发布类公众帐号使用。使用该模式,可以方便地通过界面配置“自定义菜单”和“自动回复的消息”。
好处是可视化界面配置,操作简单,快捷,但是功能有限。
- 开发模式
主要针对具备开发能力的人使用。使用该模式后,能够使用微信公众平台开放的接口,但是编辑模式的设置会失效,比如“自定义菜单”和“自动回复的消息”功能。通过编程方式可以实现更多复杂的功能,提供个性化服务。
总的来说,编辑模式就是为所有人提供的,如果你的需求仅仅只是最常见的菜单,自动回复等,使用编辑模式已经满足,但是如果你需求的功能比较复杂,有很多很多的想法,就需要使用到开发模式。
2.配置管理
操作步骤如下:
- 登陆微信公众号后台登陆地址:
- 点击开发-->基本配置
- 在基本配置页,启用开发者密码,并配置IP白名单
- 设置完成后,启用服务器配置,并填写对应的URL,token以及消息加解密密钥,选择加密方式后完成开发配置(此步可以暂时忽略,在接入验证时操作)。
在公众号配置时需要填写一些参数项,说明如下:
- appid:是公众号开发识别码,配合开发者密码可调用公众号的接口能力。
- appsecret:是校验公众号开发者身份的密码,具有极高的安全性。
- URL:就是指我们自己的服务器地址,该URL是开发者用来接收和响应微信消息和事件的接口URL(必须以http://或https://开头,分别支持80端口和443端口)。
- Token:可任意填写,用作生成签名(必须为英文或数字,长度为3-32字符)
该签名在后边会用到,这里暂时随便填个内容也可以
微信与服务器的交互过程说明
- 当我们在微信app上,给公众号发送一条内容的时候,实际会发送到微信的服务器上.
- 此时微信的服务器就会对内容进行封装成某种格式的数据比如xml格式,再转发到我们配置好的URL上,所以该URL实际就是我们处理数据的一个请求路径。
- 所以该URL必须是能暴露给外界访问的一个公网地址,不能使用内网地址.
- 生产环境可以申请腾讯云,阿里云服务器等,
- 开发环境需要利用一些软件来完成内网穿透,便于修改和测试,如NATAPP,花生壳等软件。66. 内网穿透软件使用起来很方便,在本地安装对应的软件,配置运行后,直接使用软件分配的临时域名来访问本地应用即可,只是偶尔会存在网络不稳定的情况。具体教程可参考软件官网。
3.注册测试公众号
个人订阅号有一些接口是没有权限的,也就是说个人订阅号无法调用一些高级的权限接口,如生成二维码、网页授权、自定义菜单、微信支付这样的接口权限个人订阅号是没有调用权限的, 幸运的是,微信公众平台提供了测试公众账号,测试公众号有很多个人订阅号不具备的权限。
- 测试公众号的注册地址为:测试公众号
- ++用微信扫描页面中的二维码,登陆成功后就可以看到分配的测试号++
4.创建内网穿透环境
在进入开发前,我们还要准备一个内网穿透工具来实现本地开发,因为微信需要配置一个域名来校验我们的微信服务程序和供客户端调用其接口。
推荐以下工具:
5.域名接入验证
在微信公众平台开发者文档上,关于公众号接入这一节内容在接入指南上写的比较详细的,文档中说接入公众号需要3个步骤,分别是:
- 填写服务器配置
- 验证服务器地址的有效性
- 依据接口文档实现业务逻辑
其实,第3步已经不能算做公众号接入的步骤,而是接入之后,开发人员可以根据微信公众号提供的接口所能做的一些开发。
第1步中服务器配置包含服务器地址(URL)、令牌(Token) 和 消息加解密密钥(EncodingAESKey)。
可在开发–>基本配置–>服务器配置中配置
- 服务器地址即公众号后台提供业务逻辑的入口地址即项目的返回URL(Controller方法的URL),目前只支持80端口,之后包括接入验证以及任何其它的操作的请求(例如消息的发送、菜单管理、素材管理等)都要从这个地址进入。接入验证和其它请求的区别就是,接入验证时是get请求,其它时候是post请求;
- Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)
- EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。若以明文消息方传递式,则不涉及此配置项。
第2步,验证服务器地址的有效性。
当点击“提交”按钮后,微信服务器将发送一个http的get请求到刚刚填写的服务器地址,并且携带四个参数:
参数 | 描述 |
---|---|
signature | 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。 |
timestamp | 时间戳 |
nonce | 随机数 |
echostr | 随机字符串 |
signature参数结合了开发者填写的token参数和请求中的timestamp参数、nonce参数来做的加密签名,我们在后台需要对该签名进行校验,看是否合法。
实际上,我微信带过来的4个参数中并没有带token参数,仅有signature是和token有关的,所以我们应该在本地应用中也准备一个和填入的token相同的参数,再通过微信传入的timestamp与nonce做相同算法的加密操作,若结果与微信传入的signature相同,即为合法,则原样返回echostr参数,代表接入成功,否则不做处理,则接入失败。
即接到请求后,我们需要做如下三步,若确认此次GET请求来自微信服务器,原样返回echostr参数内容,则接入生效,否则接入失败。
1. 将token、timestamp、nonce三个参数进行字典序排序
2. 将三个参数字符串拼接成一个字符串进行sha1加密 (可逆加密解密函数)
3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
相关代码:
@Controller
public class WeChatController {
/**
* 微信URL接入验证
* @param signature
* @param timestamp
* @param nonce
* @param echostr
* @return
*/
@RequestMapping(value="/weChat",method= RequestMethod.GET)
@ResponseBody
public String validate(String signature,String timestamp,String nonce,String echostr){
//1. 将token、timestamp、nonce三个参数进行字典序排序
String[] arr = {timestamp,nonce,WeChatUtil.TOKEN};
Arrays.sort(arr);
//2. 将三个参数字符串拼接成一个字符串进行sha1加密
StringBuilder sb = new StringBuilder();
for (String temp : arr) {
sb.append(temp);
}
//3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
if(SecurityUtil.SHA1(sb.toString()).equals(signature)){
//接入成功
return echostr;
}
//接入失败
return null;
}
对于raycom框架,由于集成了javawxSDK,已经设置好了验证URL,即:
//项目名即为项目访问的前缀,wecheatId是公众号表中对应的id
http://xxxx:xx/{项目名}/mp/portal/{wechatId}
开发模式下,避免因重启多次获取accessToken,直接在raycom.properties添加accessToken,即:
//{wechatId}由具体的wechatId替换
{wechatId}AccessToken=XXXXXX
到此,我们的公众号应用已经能够和微信服务器正常通信了,也就是说我们的公众号已经接入到微信公众平台了。
6. 获取access_token
我们的公众号和微信服务器对接成功之后,接下来要做的就是根据我们的业务需求调用微信公众号提供的接口来实现相应的逻辑了。在使用微信公众号接口中都需要一个access_token。
access_token介绍
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
总结以上说明,access_token需要做到以下两点:
- 因为access_token有2个小时的时效性,要有一个机制保证最长2个小时重新获取一次。
- 因为接口调用上限每天2000次,所以不能调用太频繁。
获取access_token步骤
公众号可以使用AppID和AppSecret调用本接口来获取access_token。
AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。
调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器IP地址添加到IP白名单中,否则将无法调用成功。
接口调用请求说明
https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
grant_type | 是 | 获取access_token填写client_credential |
appid | 是 | 第三方用户唯一凭证 |
secret | 是 | 第三方用户唯一凭证密钥,即appsecret |
返回说明
{"access_token":"ACCESS_TOKEN","expires_in":7200}
参数 | 说明 |
---|---|
access_token | 获取到的凭证 |
expires_in | 凭证有效时间,单位:秒 |
相关代码
@Override
public String getAccessToken(boolean forceRefresh) throws WxErrorException {
if (!this.getWxMpConfigStorage().isAccessTokenExpired() && !forceRefresh) {
return this.getWxMpConfigStorage().getAccessToken();
}
Lock lock = this.getWxMpConfigStorage().getAccessTokenLock();
lock.lock();
try {
String url = String.format(WxMpService.GET_ACCESS_TOKEN_URL,
this.getWxMpConfigStorage().getAppId(), this.getWxMpConfigStorage().getSecret());
try {
HttpGet httpGet = new HttpGet(url);
if (this.getRequestHttpProxy() != null) {
RequestConfig config = RequestConfig.custom().setProxy(this.getRequestHttpProxy()).build();
httpGet.setConfig(config);
}
try (CloseableHttpResponse response = getRequestHttpClient().execute(httpGet)) {
String resultContent = new BasicResponseHandler().handleResponse(response);
WxError error = WxError.fromJson(resultContent, WxType.MP);
if (error.getErrorCode() != 0) {
throw new WxErrorException(error);
}
WxAccessToken accessToken = WxAccessToken.fromJson(resultContent);
this.getWxMpConfigStorage().updateAccessToken(accessToken.getAccessToken(), accessToken.getExpiresIn());
return this.getWxMpConfigStorage().getAccessToken();
} finally {
httpGet.releaseConnection();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
} finally {
lock.unlock();
}
至此, access_token获取成功 !
7.总结
总结一下接入开发的过程,即代码编写完成后, 通过微信公众号测试的全过程:
- 启动内网穿透软件,开启外网访问,得到外网访问的域名
- Tomcat启动项目
- 进入微信公众号测试管理平台, 修改接口配置信息URL, 待签名校验通过,就可以测试
- 进入测试公众号, 发送消息进行测试