首页 > 学院 > 开发设计 > 正文

第 2 章 微信开发之开启开发模式和服务器配置

2019-11-15 00:38:58
字体:
来源:转载
供稿:网友
第 2 章 微信开发之开启开发模式和服务器配置

首先我们要明确开发模式什么可以做,什么不可以做:

  一、开发模式可以实现的功能

  1、可以接收用户发送过来的消息,通过你自己开发的系统把对应内容反馈回去。

  2、可以接收用户发送过来的地理位置,通过地理位置你可以反馈附近餐厅信息或交通信息(例如高德地图)

  3、通过事件推送,可以识别用户对公众帐号订阅和取消订阅操作的情况。

  4、开发模式的接口除了可以反馈图文消息,也可以反馈音频内容给用户。

  5、可以通过通用接口上传图片、语音、视频等内容到公众平台上,并且可以调用这些素材。

  6、可以管理自定义菜单功能。(该功能还在内测中)

  二、开发模式不能实现的功能

  1、不能识别用户账号名称,只能识别一串很长的ToUserName,这应该是微信公众平台对用户信息的隐私保护。所以想把用户拉到自己平台进行管理这是不可能的。

  2、不能管理用户或查看用户的个人资料。

  3、不能单独给某一用户回复消息,这个只能在微信公众平台上管理。

  4、开发模式不支持消息群发,这个也只能在微信公众平台上操作。

  目前开发模式主要应用的方式:

   1、微信其实是一个浏览器,只要你设计制作HTML5的手机页面,就可以通过微信直接访问,这样可以带给我们无限的想象空间。招商银行的微信就 是通过这样的方式实现查询余额、手机还款等功能。中国联通的微信可以查话费、查流量等等功能。当然基于这种方式我们还可以做更多的后端功能开发。

  2、微信内置的地图定位,可以实现附近交通情况、查附件餐厅酒店等信息。

  3、可以用来做微信聊天机器人,这个需要很强大的语义识别技术,这个功能很多平台都已经实现。

  4、可以通过微信买彩票,例如腾讯官方的“便民彩票”一样。

  5、状态通知功能,如果用过DNSPOD微信的朋友应该知道,他有个状态通知功能,当网站DOWN机或帐号登录,都会自动向你通报。如果这个功能得到普及,以后网站认证不需要短信了。

整体概括起来有两点 :

1).微信公众平台提供了一种网址接入的方法, 这种方法让我们把公众账号服务器地址提交给微信后台 ;

2).微信在向我们的公众账号服务器发送数据的时候会带一个加密串, 这个加密串只有我们能解密, 同时也只有微信后台能生成这个加密串。

准备的资料:

1)服务器。首先我们至少要有一台自己的服务器, 并且这台服务器要能提供服务, 就是说要能够被微信后台的服务器访问到。

2)外网的ip。这需要服务器有一个外网 IP。

3)端口需要时80的。 Web Server 监听外网 IP 的 80 端口之后就能收到微信后台的请求了。

注意 可能很多读者希望能在自己的 PC 机上做接入的测试, 但是笔者建议不要这么做, 因为这可能会遇到很多的麻烦。 如果你的确想这么做, 请注意以下事情:1) 一般学校宿舍都是使用内网 IP 的, 如果你是住在学校宿舍, 直接放弃吧。2) 家里路由器一般是通过 NAT 的方式工作的, 所以如果你的 PC 机是通过路由器上网的话分配到的也是一个内网 IP, 不能对外提供服务。 这个时候可尝试把路由器的接入网线直接插到电脑上来获取外网 IP 联网。3) 如果第 2 步尝试失败(验证方法 : 在其他电脑上通过浏览器访问你本地 WebServer), 请联系你的网络服务提供商(电信、 联通、 铁通、 长城宽带、 天威宽带等), 询问他们提供给你的 IP 是否做了 NAT 转发, 如果是, 则可在允许的情况下要求他们给你一个不做 NAT 转发的 IP。4) 如果完成第 3 步还未能成功, 那么你和笔者的遭遇是一样的。 笔者确认了很多次, 确定自己的本地 Web Server 配置是没有问题的, 然后打电话给网络提供商,他们并没有给一个合理的回答, 毕竟他们很少遇到这么做的用户。 笔者猜测他们可能为了安全, 阻挡了所有的对他们家庭用户 IP 的主动连接。 那怎么解决这个问题呢? 笔者建议读者购买一个 linux 的网络主机, 最好是可以直接登录的, 而不是那种准备好了环境, 只提供上传代码功能的网络空间。 笔者购买了阿里云的服务器和 MySQL 实例, 用起来还是很不错的, 而且阿里云的服务也很好。

另外一个问题, 为什么要绑定 80 端口? 公网的环境非常复杂, 我们的公众账号服务器和微信后台的数据传输要经过很多的路由器, 这些路由器都有各自的安全设置, 其中有一些会把所有的非 80 端口的包直接丢弃。 如果我们使用非 80 端口就会出现我们发给微信后台的包对方收不到的情况。 反过来也是一样的

首先登录我们自己的公众账号的前台(http://mp.weixin.QQ.com/), 接着依次单击导航上的“ 高级功能” →右边的“ 开发模式” →“ 成为开发者”。

服务器的配置:

几个字段的解释:可以参考官网解答。官方开发文档

第一步:填写服务器配置

登录微信公众平台官网后,在公众平台后台管理页面 - 开发者中心页,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey。

URL:开发者用来接收微信消息和事件 的接口URL。URL指的是能够接收处理微信服务器发送的GET/POST请求的地址,并且是已经存在的,现在就能够在浏览器访问到的地址,这就要求我们先把公众帐号后台处理程序开发好(至少应该完成了对GET请求的处理)并部署在公网服务器上。

Token:可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性);Token 是一个任意的字符串, 你提交 Token 给微信后台之后, 只有你和微信后台知道这个字符串是什么, 也就是只有微信后台和我们的公众账号服务器知道这个字符串。 于是 Token 就成了这两台服务器之间的密钥, 它可以让公众账号服务器确认请求是来自微信后台还是恶意的第三方。

EncodingAESKey:开发者手动填写或随机生成,将用作消息体加解密密钥。

开发者可选择消息加解密方式:明文模式、兼容模式和安全模式。

第二步:验证服务器地址的有效性

1) 微信后台在发送数据给公众账号服务器的时候, 会额外带上 3 个参数 :signature、 timestamp、 nonce。 其中 timestamp 是 时 间 戳、 nonce 是 一 个 随 机 数、signature 是对 timestamp、 nonce 和 Token 进行 SHA1 加密后的字符串。 SHA1 的加密过程是不可逆的, 即不能通过 signature、 timestamp 和 nonce 计算出 Token 是什么。2) 在公众账号服务器收到 timestamp、 nonce 和 signature 之后, 同样对 nonce、timestamp 和 Token 使用 SHA1 加密算法, 得到自己的签名, 如果自己的签名和请求中的 signatrue 是一样的, 那么说明请求是来自微信后台而不是恶意第三方。

---------------------------------------------------

注意 恶意的第三方有可能会截获到微信后台发过来的 signature、 timestamp 和nonce 三个参数, 然后直接用这个三个参数来对公众账号服务器发起请求。 按照上面的逻辑是无法判断的出这是个恶意的请求。 这种攻击称为“ replay 攻击”。 这种攻击方式的防御方法很简单 : 加上对 timestamp 的校验。 收到请求之后, 我们将请求包中的 timestamp 和当前时间比较, 如果误差大于一定的值就可以认为这个请求是恶意的。 这里不能做相等的比较, 因为数据在网络上传输需要时间, 同时各个服务的本地时间也是有一些差异的。

---------------------------------------------------

开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带四个参数:

参数描述
signature微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
timestamp时间戳
nonce随机数
echostr随机字符串

开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。

我们写一个CoreServlet 类来接收微信服务器传来的几个参数:

package com.souvc.weixin.servlet;import java.io.IOException;import java.io.PRintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.souvc.weixin.util.SignUtil;/** *  * @ClassName: CoreServlet * @Description: * @author: souvc * @date Jun 15, 2015 11:25:36 AM */public class CoreServlet extends HttpServlet {    private static final long serialVersionUID = 4440739483644821986L;    /**     * 确认请求来自微信服务器     */    public void doGet(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        // 微信加密签名        String signature = request.getParameter("signature");        // 时间戳        String timestamp = request.getParameter("timestamp");        // 随机数        String nonce = request.getParameter("nonce");        // 随机字符串        String echostr = request.getParameter("echostr");        PrintWriter out = response.getWriter();        // 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败        if (SignUtil.checkSignature(signature, timestamp, nonce)) {            out.print(echostr);        }        out.close();        out = null;    }    /**     * 处理微信服务器发来的消息     */    public void doPost(HttpServletRequest request, HttpServletResponse response)            throws ServletException, IOException {        // TODO 消息的接收、处理、响应    }}

然后需要写一个验证微信服务器传过来的token跟服务器设置的是否一致。

加密/校验流程如下:1. 将token、timestamp、nonce三个参数进行字典序排序2. 将三个参数字符串拼接成一个字符串进行sha1加密3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

我们把它封装成一个工具类 SignUtil :

package com.souvc.weixin.util;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Arrays;/** *  * @ClassName: SignUtil * @Description: * @author: souvc * @date Jun 15, 2015 11:25:18 AM */public class SignUtil {    // 与接口配置信息中的Token要一致    private static String token = "souvcweixin";    /**     * 验证签名     *      * @param signature     * @param timestamp     * @param nonce     * @return     */    public static boolean checkSignature(String signature, String timestamp,            String nonce) {        String[] arr = new String[] { token, timestamp, nonce };        // 将token、timestamp、nonce三个参数进行字典序排序        Arrays.sort(arr);        StringBuilder content = new StringBuilder();        for (int i = 0; i < arr.length; i++) {            content.append(arr[i]);        }        MessageDigest md = null;        String tmpStr = null;        try {            md = MessageDigest.getInstance("SHA-1");            // 将三个参数字符串拼接成一个字符串进行sha1加密            byte[] digest = md.digest(content.toString().getBytes());            tmpStr = byteToStr(digest);        } catch (NoSuchAlgorithmException e) {            e.printStackTrace();        }        content = null;        // 将sha1加密后的字符串可与signature对比,标识该请求来源于微信        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;    }    /**     * 将字节数组转换为十六进制字符串     *      * @param byteArray     * @return     */    private static String byteToStr(byte[] byteArray) {        String strDigest = "";        for (int i = 0; i < byteArray.length; i++) {            strDigest += byteToHexStr(byteArray[i]);        }        return strDigest;    }    /**     * 将字节转换为十六进制字符串     *      * @param mByte     * @return     */    private static String byteToHexStr(byte mByte) {        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',                'B', 'C', 'D', 'E', 'F' };        char[] tempArr = new char[2];        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];        tempArr[1] = Digit[mByte & 0X0F];        String s = new String(tempArr);        return s;    }}

配置一下访问路径的 web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">    <servlet>        <servlet-name>coreServlet</servlet-name>        <servlet-class>            com.souvc.weixin.servlet.CoreServlet        </servlet-class>    </servlet>    <!-- url-pattern中配置的/coreServlet用于指定该Servlet的访问路径 -->    <servlet-mapping>        <servlet-name>coreServlet</servlet-name>        <url-pattern>/coreServlet</url-pattern>    </servlet-mapping>    <!-- 配置400,404,500异常处理 -->    <error-page>        <error-code>400</error-code>        <location>/error/404.jsp</location>    </error-page>    <error-page>        <error-code>404</error-code>        <location>/error/404.jsp</location>    </error-page>    <error-page>        <error-code>405</error-code>        <location>/error/404.jsp</location>    </error-page>    <error-page>        <error-code>500</error-code>        <location>/error/404.jsp</location>    </error-page>    <error-page>        <error-code>505</error-code>        <location>/error/404.jsp</location>    </error-page>    <welcome-file-list>        <welcome-file>index.jsp</welcome-file>    </welcome-file-list></web-app>

部署到公网的服务器上面。

注意如果直接访问这个地址(http://souvc.com/coreServlet)的话,是会报错误的,因为我们这样访问没有传参数过去,会报500的错误。

我们需要通过微信服务器里面的配置来进行。

把这个代码打包上传到sae,bae,ace,或是自己的公网服务器即可进行访问,然后进行验证。

第三步:依据接口文档实现业务逻辑

后面接上。

源码分享:

http://yunpan.cn/cQyyUMFWqkiR4 访问密码 ffd8


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表