微信开发者接入官方文档 : https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319
一、微信公共号通讯机制
作为开发者,我们需要面对的主要有两个对象:微信服务器和应用程序(网站)服务器。
当微信用户向你的公众平台发送一条消息,实际上这条消息首先发送到微信服务器,由微信服务器向网站服务器(我们开发的后台服务)发起另外一个请求,网站服务器返回这个请求的结果,再由微信服务器发送到微信客户端。
整个消息通讯流程如下图:
具体请求流程见下图:
二、 外网映射工具(开发调试)
1、 外网映射工具
微信公众平台在访问后台时,必须提供能够正确访问的外网地址,因为我们在本地开发,IP:127.0.0.1 ,所以要通过内网穿透,提供给外网的微信公众平台正确访问,微信平台对后台URL的要求有两点:
① 必须能够用公网访问 ② 必须使用80端口
方式:通过免费的映射工具。
(1)natapp
官网 :https://natapp.cn/
(2)ngrok
官网:https://www.ngrok.cc/
(3)nat123
官网:http://www.nat123.com/
(4)花生壳
使用花生壳外网映射的可以参考这篇博客:http://www.souvc.com/?p=2272
2、我这里选择的是ngrok外网映射工具
使用ngrok:
(1)、ngrok下载: 链接:https://pan.baidu.com/s/1PeVRF2lfNoQYro3YJW_7JQ 密码:s7bm
b、切换到该目录下执行上述命令
c、本地服务映射成到外网成功效果图
二、填写服务器配置信息的介绍
1、登录微信公众平台官网后,进入到公众平台后台管理页面。
选择 公众号基本设置-》基本配置 ,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey。
微信公众号配置界面:
服务器配置:
URL:是开发者用来接收微信消息和事件 的接口URL。(http://公网地址/项目名称/请求路径)
Token:可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。注意必须为英文或数字,长度为3-32字符,在校验的时候需要用到,随便输入一个字符串就可以了。
EncodingAESKey:由开发者手动填写或随机生成,将用作消息体加解密密钥。(消息加密密钥由43位字符组成,可随机修改,字符范围为A-Z,a-z,0-9。)
开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带四个参数
参数 描述
signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp 时间戳
nonce 随机数
echostr 随机字符串
2、编写相应的Controller(采用spring MVC)
package com.thinkgem.jeesite.modules.app.api;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
/**
*
* @ClassName: WeiXinController
* @Description: TODO(对微信请求校验,成为开发者)
* @author CaoWenCao
* @date 2018年6月6日 下午2:09:38
*/
@Controller
@RequestMapping(value = "weixin")
public class WeiXinController {
private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
@RequestMapping(value = "getWeiXinMethod", method = RequestMethod.GET)
@ResponseBody
public void getWeiXinMethod(HttpServletRequest request, HttpServletResponse response) throws IOException {
boolean validate = validate(request);
if (validate) {
response.getWriter().write(request.getParameter("echostr"));
response.getWriter().close();
}
}
private boolean validate(HttpServletRequest req) throws IOException {
String signature = req.getParameter("signature");// 微信加密签名
String timestamp = req.getParameter("timestamp");// 时间戳
String nonce = req.getParameter("nonce");// 随机数
List<String> list = new ArrayList<String>();
list.add("caowencao");
list.add(timestamp);
list.add(nonce);
Collections.sort(list);// 字典排序
String str = "";
for (int i = 0; i < list.size(); i++) {
str += (String) list.get(i);
}
if (encode("SHA1", str).equalsIgnoreCase(signature)) {
return true;
}
else {
return false;
}
}
public static String encode(String algorithm, String str) {
if (str == null) {
return null;
}
try {
// Java自带的加密类
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
// 转为byte
messageDigest.update(str.getBytes());
return getFormattedText(messageDigest.digest());
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String getFormattedText(byte[] bytes) {
int len = bytes.length;
StringBuilder buf = new StringBuilder(len * 2);
// 把密文转换成十六进制的字符串形式
for (int j = 0; j < len; j++) {
buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
}
return buf.toString();
}
}
3、点击提交按钮,此时验证和调用没问题,已经成功接入开发者模式。