概述
微信公众号的集成现在在很多业务上都需要。看着官方一大堆的 文档,大家可能不知道如何下手。本篇从 api
入手和大家一起了解下公众号在业务上如何集成。
基础环境
公众号的开发需要认证的服务号,不过官方也提供了 测试帐号 供开发测试。
开发过程中需要的环境如下:
- 测试号
- 公网
内网穿透
公网主要用于接收微信推送消息,比方有新用户关注、取消关注等事件。
如果大家没有公网,可以通过内网穿透来本机调试。比较常用的有 ngrok
、Sunny-Ngrok
、natapp
、花生壳
等。
笔者这里用的 Sunny-Ngrok
免费版,不过网络不稳定,经常断开。
测试号
验证 接口配置信息
, 需要启动程序响应公众平台验证。验证通过即可响应公众平台事件消息, 比方说 关注事件
, 然后将微信用户与平台用户进行 绑定
。
回调域名配置。编辑网页服务-网页帐号,配置如下:
回调验证
这里基于 Java
实现,笔者采用的 SpringBoot
。
application.properties
server.port=80
wx.appID=wx3f2f5354f615c639
wx.appsecret=80ae2299328c6c8f6ae0c774a69b08b0
wx.token=123456
工具类
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class SHA1 {
public static String gen(String... arr) {
Arrays.sort(arr);
StringBuilder sb = new StringBuilder();
String[] parr = arr;
int size = arr.length;
for(int i = 0; i < size; ++i) {
String a = parr[i];
sb.append(a);
}
return sha1(sb.toString());
}
public static String sha1(String str) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update(str.getBytes());
byte[] messageDigest = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
// 字节数组转换为 十六进制 数
for (int i = 0; i < messageDigest.length; i++) {
String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
if (shaHex.length() < 2) {
hexString.append(0);
}
hexString.append(shaHex);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}
/**
* 签名校验
* @param timestamp
* @param nonce
* @param signature
* @return
*/
public boolean checkSignature(String timestamp, String nonce, String signature) {
try {
return SHA1.gen(new String[]{wxConfig.getToken(), timestamp, nonce}).equals(signature);
} catch (Exception e) {
logger.error("签名校验失败: {}", e.getMessage());
return false;
}
}
签名校验与回调消息接收
@RestController
@RequestMapping("/weixin/sign")
public class WxPortalController {
private static final Logger logger = LoggerFactory.getLogger(WxPortalController.class);
@Autowired
private WxService wxService;
/**
*
* @param signature 微信加密签名
* @param timestamp 时间戳
* @param nonce 随机数
* @param echostr 随机字符串
* @return
*/
@GetMapping(produces = "text/plain;charset=utf-8")
public String authGet(@RequestParam(name = "signature", required = false) String signature,
@RequestParam(name = "timestamp", required = false) String timestamp,
@RequestParam(name = "nonce", required = false) String nonce,
@RequestParam(name = "echostr", required = false) String echostr) {
logger.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature,
timestamp, nonce, echostr);
if (wxService.checkSignature(timestamp, nonce, signature)) {
return echostr;
}
return "非法请求";
}
/**
*
* @param requestBody 回调消息
* @param signature
* @param timestamp
* @param nonce
* @param openid
* @param encType
* @param msgSignature
* @return
*/
@PostMapping(produces = "application/xml; charset=UTF-8")
public String post(@RequestBody String requestBody,
@RequestParam("signature") String signature,
@RequestParam("timestamp") String timestamp,
@RequestParam("nonce") String nonce,
@RequestParam("openid") String openid,
@RequestParam(name = "encrypt_type", required = false) String encType,
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
// 获取到openId
logger.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
try {
wxService.handleEvent(requestBody);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
至此,微信的基本开发就 ok 了。大家可以根据回调事件的消息做相应的业务处理。
接口分析
获取 access_token
基本所有的接口调用都需要 access_token
。
GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=wx3f2f5354f615c639&secret=80ae2299328c6c8f6ae0c774a69b08b0
Response
{
"access_token": "32_S2GVg7DuHc1VxsHY5Hf9kdqCCP1BBI9pBv-ZvK_JHtN1HTjXyN0NmIPYvRHZwkiHy7cDA_944K9V0WU3_XC3GuL8Q8rVF93PDXGDZpuN8-3V6gKFELbEnrF-sN-Ps24he8zrQs8Db_gxqrtYULKeAFAYPO",
"expires_in": 7200
}
基于 Oauth2 获得授权码,需要在微信客户端打开
GET
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx3f2f5354f615c639&redirect_uri=http://idcmind.com/weixin/sign&response_type=code&scope=snsapi_base&state=STATE
Java 代码 web 接口
@RestController
@RequestMapping("/weixin/code")
public class WxCodeController {
private static final Logger logger = LoggerFactory.getLogger(WxCodeController.class);
@GetMapping
public Object code(@RequestParam("code") String code, @RequestParam("state") String state) {
logger.info("code={}, state={}", code, state);
return code;
}
}
微信端访问日志
code=061PRu4d2jOFiH0Kh83d2Hig4d2PRu4m, state=123456
获取 OpenId
GET
带入刚才获得的 code
https://api.weixin.qq.com/sns/oauth2/access_token?appid=wx3f2f5354f615c639&secret=80ae2299328c6c8f6ae0c774a69b08b0&code=061PRu4d2jOFiH0Kh83d2Hig4d2PRu4m&grant_type=authorization_code
Response
{
"access_token": "32_kCTsG4G6Vp-p2NWQQbelmpTshAHldad7XNBf9FFAtUn6QwhNHuFIM9utpRaabhn4NcT5ObK4XY4_Hc3wWPf5nMVs0zqXtOL5YJvB7Lk2XBg",
"expires_in": 7200,
"refresh_token": "32_oO-cHAoZdugyzJ0uvi49_E81PsddQdO7pBSGjjlmxZqRcXBGqu1aVHQRu4TW_T7_FuGMF4te3CxtCvc7H_21tfqOPWSJMEalhBrgQ3Is8K4",
"openid": "oHOLJw-r6lBxSXU4pRDKpoDyqWI0",
"scope": "snsapi_base"
}
openid
是微信用户在 公众号
的唯一身份标识。
获取用户基本信息(UnionID 机制)
GET
https://api.weixin.qq.com/cgi-bin/user/info?access_token=32_ybQmVgsXDCHKSiG3bRIL7xRq1Y39sKVylwUOMQls8IKlpY5dqiycEPvQmzBvsl2REtAi11WUSn5Nc29ZnOddO0V8Rll0RtKw6WLtwgzhr3_4h5-I1pGShVa1KuD1GQXcPIKblSae5Bt8PkxiVEHjACAFOR&openid=oHOLJw-r6lBxSXU4pRDKpoDyqWI0&lang=zh_CN
Response
{
"subscribe": 1,
"openid": "oHOLJw-r6lBxSXU4pRDKpoDyqWI0",
"nickname": "当我遇上你",
"sex": 1,
"language": "zh_CN",
"city": "朝阳",
"province": "北京",
"country": "中国",
"headimgurl": "http://thirdwx.qlogo.cn/mmopen/RFKUCMNiaHBDu2OOyCcvq5uTIteIlicusVTVUVNtIicjSyNY2su0eSYAIUzDtlAkE3Ff6uaKN8UvryLwicX1c2OeLNHJR3ibBeo9G/132",
"subscribe_time": 1587187948,
"remark": "",
"groupid": 0,
"tagid_list": [],
"subscribe_scene": "ADD_SCENE_QR_CODE",
"qr_scene": 0,
"qr_scene_str": "1234567"
}
获取用户列表
GET
https://api.weixin.qq.com/cgi-bin/user/get?access_token=32_ybQmVgsXDCHKSiG3bRIL7xRq1Y39sKVylwUOMQls8IKlpY5dqiycEPvQmzBvsl2REtAi11WUSn5Nc29ZnOddO0V8Rll0RtKw6WLtwgzhr3_4h5-I1pGShVa1KuD1GQXcPIKblSae5Bt8PkxiVEHjACAFOR
Response
{
"total": 1,
"count": 1,
"data": {
"openid": [
"oHOLJw-r6lBxSXU4pRDKpoDyqWI0"
]
},
"next_openid": "oHOLJw-r6lBxSXU4pRDKpoDyqWI0"
}
生成带参数的二维码
这里演示带字符串参数的永久二维码
POST
https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=32_9o3KwEVvZho6PxWqnmhVpUNiWcaGpgl_TvvJH1NHS_3ZAPQl-2dh4XCqbxdqtahdd39hKTP9kYAcnr2Jmu1-V7n0szIdiAkoHZmd0BGOUGHrSro4i4oY0I2I4zPxcPfXxmsTJKrvlotsvwjBALCbAAAPAR
请求体
{
"action_name": "QR_LIMIT_STR_SCENE",
"action_info": {
"scene": {
"scene_str": "1234567"
}
}
}
Response
{
"ticket": "gQG18TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyTGhyV01tc3lmOTMxMDAwMGcwN24AAgTQippeAwQAAAAA",
"url": "http://weixin.qq.com/q/02LhrWMmsyf9310000g07n"
}
通过 ticket 换取二维码
GET
https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQG18TwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAyTGhyV01tc3lmOTMxMDAwMGcwN24AAgTQippeAwQAAAAA
Response
基于字节流的图片,在浏览器访问上诉地址即可渲染出二维码。该二维码是带参数的二维码,扫码关注后回调消息中会携带参数。比如按 userId
生成二维码,扫码关注后回调消息包含 openid
和 userid
, 可以用于后续绑定操作。
用户关注后 java 后台会收到 xml 消息:
1587187948
新增临时素材
POST
https://api.weixin.qq.com/cgi-bin/media/upload?access_token=32_LtMp7FPdxSvV1kmPHoQTqCjhGAjigFDvhzVPnAIQsknmHyFOtTO9g5XBr7DVVNPepYLPZjSRCX0fDKZqTzBufliVoWTMmRI1Uu-T2aMt3vfTzlluzm6eANZ6nJNEa_BXLwHxIx3yLP49fr_MZTZfACAGAG&type=image
Content-Type:multipart/form-data
body 中选择 file 类型的 key,value 选择本地图片
Response
{
"type": "image",
"media_id": "51TAwv-DI7RucNhJr8tzqbYLWSZFH-m1b40Td2rLz3L2WUo881sQ8DgGxeRKXMG5",
"created_at": 1587187471,
"item": []
}
获取临时素材
GET
https://api.weixin.qq.com/cgi-bin/media/get?access_token=32_LtMp7FPdxSvV1kmPHoQTqCjhGAjigFDvhzVPnAIQsknmHyFOtTO9g5XBr7DVVNPepYLPZjSRCX0fDKZqTzBufliVoWTMmRI1Uu-T2aMt3vfTzlluzm6eANZ6nJNEa_BXLwHxIx3yLP49fr_MZTZfACAGAG&media_id=51TAwv-DI7RucNhJr8tzqbYLWSZFH-m1b40Td2rLz3L2WUo881sQ8DgGxeRKXMG5
Response
返回图片素材
获取模板列表
创建模板不需要调用接口,在公众号后台即可设置。
我创建的模板如下:
欢迎你: {{name.DATA}}
GET
https://api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=32_ybQmVgsXDCHKSiG3bRIL7xRq1Y39sKVylwUOMQls8IKlpY5dqiycEPvQmzBvsl2REtAi11WUSn5Nc29ZnOddO0V8Rll0RtKw6WLtwgzhr3_4h5-I1pGShVa1KuD1GQXcPIKblSae5Bt8PkxiVEHjACAFOR
Response
{
"template_list": [
{
"template_id": "7BsKKP1MsDxbNmfYfTaNVm9guRvgwH8l2PmFbDCMip0",
"title": "欢迎模板",
"primary_industry": "",
"deputy_industry": "",
"content": "欢迎你: {{name.DATA}}",
"example": ""
}
]
}
发送模板消息
POST
https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=32_ybQmVgsXDCHKSiG3bRIL7xRq1Y39sKVylwUOMQls8IKlpY5dqiycEPvQmzBvsl2REtAi11WUSn5Nc29ZnOddO0V8Rll0RtKw6WLtwgzhr3_4h5-I1pGShVa1KuD1GQXcPIKblSae5Bt8PkxiVEHjACAFOR
请求体
{
"touser":"oHOLJw-r6lBxSXU4pRDKpoDyqWI0",
"template_id":"7BsKKP1MsDxbNmfYfTaNVm9guRvgwH8l2PmFbDCMip0",
"url":"http://idea360.cn",
"data":{
"name": {
"value":"登高射太阳!",
"color":"#173177"
}
}
}
查看微信,会看到测试号给推送了一条模板消息。
同时,我们的 java 日志中会看到收到 xml 消息
1587188459
1301848003480829954
发送客服消息
POST
https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=32_LBmSoFhAku0mBL8dQ3mj4pSPSe6_EFBGUt_uCEu3ZGZX-auOe9etVmtKBfwnK9FgMd9BsrTWKo-mmgy86EVCjJkpvuu2h6_VZXJ_S-fCHtW7VJIKlQ9P7tNEDlWEwDsTCUCN6Cj8dVJqK4e5PNViAJAKIQ
消息体
{
"touser":"oHOLJw-r6lBxSXU4pRDKpoDyqWI0",
"msgtype":"text",
"text":
{
"content":"Hello World"
}
}
Response
{
"errcode": 0,
"errmsg": "ok"
}
查看公众号会看到消息。
最后
本文到此结束,感谢阅读。欢迎关注公众号【当我遇上你】, 您的支持是我最大的动力。