微信公众号开发技术要点

微信公众号开发技术要点

本文将介绍微信公众号开发中涉及的一些技术概念,以便读者可以快速掌握公众号开发过程中的基本操作和流程。文档不涉及具体开发技术和流程的介绍,该文档作用相当于官方文档中关键点的详细注解。

在公众号开发流程中,涉及到三种系统:

  1. 微信方面的系统,负责监听用户的操作并将相关消息和事件推送到响应系统,下称微信系统;
  2. 接收微信系统所推送的事件和消息的系统,下称响应系统;
  3. 业务逻辑系统,实现业务逻辑处理,下称业务系统。

响应系统和业务系统需要自己开发;其中业务系统中的页面即为下文中提到的第三方页面;

微信公众号及其接口功能介绍

基本概念

公众号是为微信用户提供资讯和服务的平台;公众平台开发接口则是通过后台业务系统向用户提供服务的基础;

不同的公众号类型有不同数量的接口权限,服务号要多于订阅号;

公众号开发者模式

开启公众号开发模式后,微信系统将以事件推送的形式告知响应系统用户在公众号里的相关行为,包括:关注/取关事件、二维码扫描事件、自定义菜单事件、跳转链接事件时的事件、点击菜单拉取消息时的事件,从而开发者可以获取到该消息并做出响应;

  1. 开启公众号开发者模式
  2. 填写服务器配置
  3. 验证服务器地址的有效性

这些步骤都是在微信官方公众号后台里开发->基本配置里完成的

代码验证及图示

配置图示:

这里写图片描述

服务器代码:

public class WeChatServer extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        PrintWriter writer=resp.getWriter();
        System.out.println(req.getParameter("echostr"));
        writer.println(req.getParameter("echostr"));
    }
}
//微信系统对响应系统地址的有效性验证是通过返回值(echostr)完成的,这里没有添加对微信系统身份的检查,直接输出

完整代码见WeChatWebSystem

Open ID与Union ID

基本概念

为识别用户,微信为每一个用户提供了针对特定公众号平台的Open ID;同一个用户在不同公众号里的有不同的Open ID;同一个公众号里不同用户有不同的Open ID;获取用户的Open ID是无需用户同意的,但是获取用户的基本信息(所在地址、昵称等)是需要用户同意的;

为了实现在多个公众平台、移动应用之间做到用户统一管理,提供了Union ID机制。同一用户在同一开放平台账号下的所有公众号和应用里Union ID是相同的;

使用说明

  1. Open ID的获取和使用

    获取

    1. Open ID会在微信系统向响应系统推送普通消息以及事件推送时附带于消息体内;
    2. 从公众号进入第三方页面时,业务系统需要获得该用户的Open ID;

    使用:

    1. 发送被动消息时(包括对事件的响应和消息的响应),使用Open ID来标记发送对象;
    2. 发送主动消息时(模板消息),使用Open ID来标记发送对象;
  2. Union ID的获取和使用

    从公众号进入第三方页面时,业务系统可以选择获取Union ID来实现业务逻辑,其具体流程为:

    准备阶段:

    1. 获得微信网页授权:微信公众号后台->开发->接口权限;
    2. 设置授权回调域名:一旦设置成功,该域名下的所有页面均可以进行OAuth2.0鉴权;
    3. 以snsapi_userInfo为scope发起授权以获得该用户的基本信息;

    获取阶段:

    1. 引导用户进入授权页面,用户同意后,获得code;

      https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
      
      其中APPID/REDIRECT_URI/SCOPE/STATE为变量,参数顺序不可改变;跳转回调的redirect_uri,应当使用https链接来确保授权code的安全性。以上链接需要自微信客户端里打开,如果用户同意授权,则页面跳转到:redirect_uri/?code=CODE&state=STATE
      
      参数    是否必须    说明
      appid 是   公众号的唯一标识
      redirect_uri  是   授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理
      response_type 是   返回类型,请填写code
      scope 是   应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
      state 否   重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
      
      #wechat_redirect  是   无论直接打开还是做页面302重定向时候,必须带此参数
      
    2. 使用code换取网页授权access_token(用于获取用户基本信息的token,不是微信基础服务里的access_token,在这一步里,获取access_token的同时也会获得用户的open ID);

      获取code后,请求以下链接获取access_token:  https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
      
      其中APPID/SECRET/CODE为变量
      
      正确返回的JSON数据如下:
      { "access_token":"ACCESS_TOKEN",
      "expires_in":7200,
      "refresh_token":"REFRESH_TOKEN",
      "openid":"OPENID",
      "scope":"SCOPE" }
    3. 如有必要,开发者刷新该access_token,避免过期;

      获取第二步的refresh_token后,请求以下链接获取access_token:
      https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
      
      access_token拥有较短的有效期,refresh_token则有30天的有效期;
      
      返回结果同上
      { "access_token":"ACCESS_TOKEN",
      "expires_in":7200,
      "refresh_token":"REFRESH_TOKEN",
      "openid":"OPENID",
      "scope":"SCOPE" }
    4. 通过access_token和openID获得用户基本信息;

      https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
      
      access_token为网页授权时使用的access_token,不是调用微信接口时使用的access_token;
      返回数据:
      {    "openid":" OPENID",
      " nickname": NICKNAME,
      "sex":"1",
      "province":"PROVINCE"
      "city":"CITY",
      "country":"COUNTRY",
      "headimgurl":    "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
      "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
      "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
      }
      

    从响应系统内获得Union ID是通过其他接口实现的:

   请求方式: GET
   请求地址:https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
   参数说明:access_token即为接口访问令牌,openid即为消息的发送者
  1. 注意事项

    使用snaapi_base为scope的网页授权对用户是静默的,用户感觉直接进入了公众号网页;

    对于已关注公众号的用户,如果用户从公众号会话或者自定义菜单进入网页授权页,即使scope为snaapi_userInfo,也是静默的;

Access_token

基本介绍

access_token是公众号内全局唯一接口调用凭据;其有效期为2小时,需要定时刷新,重新获取将导致上次access_token失效;

注意事项

  1. 建议公众号使用统一的中控服务器来获取和刷新access_token;
  2. access_token的有效期通过expire_in标志;在刷新过程中中控服务器可以继续对外输出旧的access_token,刷新完毕5分钟内新旧access_token都有效;
  3. 中控服务器应当提供被动刷新access_token的机制;
  4. 公众号和小程序均可以使用AppID和AppSecret调用本接口来获取access_token;

获取流程

https请求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

正确返回结果
{"access_token":"ACCESS_TOKEN","expires_in":7200}
出粗返回结果
{"errcode":40013,"errmsg":"invalid appid"}

代码验证及图示

下图为访问失败时的截图,因为本地开发中使用的IP地址不在公众号后台的IP访问白名单所致,正式部署后将不存在该问题:

这里写图片描述

下图为服务器端浏览器接口调试页面

这里写图片描述

自定义菜单

开启服务模式后,将无法在微信公众号后台内实现对菜单的自定义,但是微信公众号后台内可以自定义的菜单点击类型十分有限(2/10),可以通过使用微信提供的菜单管理接口来对菜单进行管理。

基本介绍

  1. 微信公众号内允许3个一级菜单,每个一级菜单允许5个二级子菜单;一级菜单最多4个汉字,二级菜单最多7个汉字;
  2. 菜单项共有10种类型:
    1. click:当用户点击该类子菜单时,微信系统将向响应系统推送类型为event的消息并附带该菜单项的key值,开发者可以据此对该事件做出响应;
    2. view:当用户点击该类子菜单时,微信客户端将打开开发者在该菜单项中设置的网页URL,在该URL内开发者可以配合网页授权接口获得用户的基本信息以开展业务服务;
    3. scancode_push:当用户点击此类型子菜单时,微信客户端将调起扫一扫工具,并将结果展示给用户,如果识别结果为URL,将进入该URL,同时响应系统将接收到该消息;
    4. scancode_waitmsg:当用户点击该类子菜单时,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具,然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
    5. pic_sysphoto:当用户点击该类子菜单时,微信客户端将调起系统相机,完成拍照操作后,将拍摄的图片发送给响应系统,同时收起系统相机,等待开发者下发消息;
    6. pic_photo_or_album:基本功能同上,但是会给用户两种选择:拍照或者系统相册上传;
    7. pic_weixin:基本功能同上,但是会使用微信相册;
    8. location_select:弹出地理位置选择器,完成操作后,将选择地理信息发送给响应系统,收起地理位置选择器后,等待开发者下发消息;
    9. media_id:当用户点击该类子菜单项后,微信系统将对应永久素材id的素材下发给用户;
    10. view_limited:当用户点击该类型子菜单时,微信客户端将打开开发者在按钮中填写的永久素材id对应的图文消息URL;

创建菜单

接口说明:

 接口地址:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
 访问方式:POST
 参数说明:
 ACCESS_TOKEN即为获取的access_token;
 POST的数据为JSON字符串,其中button定义了菜单,为一个JSON数组;数组中每一个元素都是一个一级菜单,其中sub_button属性为该一级菜单的二级菜单,同样也是JSON数组;每一个菜单项包含type(上面提到的10种)、name、key等信息。
 {
     "button":[
     {    
          "type":"click",
          "name":"今日歌曲",
          "key":"V1001_TODAY_MUSIC"
      },
      {
           "name":"菜单",
           "sub_button":[
           {    
               "type":"view",
               "name":"搜索",
               "url":"http://www.soso.com/"
            },
            {//跳转小程序
                 "type":"miniprogram",
                 "name":"wxa",
                 "url":"http://mp.weixin.qq.com",
                 "appid":"wx286b93c14bbf93aa",
                 "pagepath":"pages/lunar/index"
             },
            {
               "type":"click",
               "name":"赞一下我们",
               "key":"V1001_GOOD"
            }]
       }]
 }
 正确返回消息:
 {"errcode":0,"errmsg":"ok"}
 出错时返回消息:
 {"errcode":40018,"errmsg":"invalid button name size"}

这里需要注意的是,POST的内容类型(content-type)需要设置为application/json;

查询菜单

创建自定义菜单后,可使用该接口查询自定义菜单的结构。如果使用了个性化菜单,那么该接口将返回默认菜单和全部个性化菜单的信息;

请求方式:GET
https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN

返回数据(无个性化菜单时):
{
    "menu": {
        "button": [
            {
                "type": "click", 
                "name": "今日歌曲", 
                "key": "V1001_TODAY_MUSIC", 
                "sub_button": [ ]
            }, 
            {
                "type": "click", 
                "name": "歌手简介", 
                "key": "V1001_TODAY_SINGER", 
                "sub_button": [ ]
            }, 
            {
                "name": "菜单", 
                "sub_button": [
                    {
                        "type": "view", 
                        "name": "搜索", 
                        "url": "http://www.soso.com/", 
                        "sub_button": [ ]
                    }, 
                    {
                        "type": "view", 
                        "name": "视频", 
                        "url": "http://v.qq.com/", 
                        "sub_button": [ ]
                    }, 
                    {
                        "type": "click", 
                        "name": "赞一下我们", 
                        "key": "V1001_GOOD", 
                        "sub_button": [ ]
                    }
                ]
            }
        ]
    }
}

返回结果(有个性化菜单时):
{
    "menu": {
        "button": [
            {
                "type": "click", 
                "name": "今日歌曲", 
                "key": "V1001_TODAY_MUSIC", 
                "sub_button": [ ]
            }
        ], 
        "menuid": 208396938
    }, 
    "conditionalmenu": [
        {
            "button": [
                {
                    "type": "click", 
                    "name": "今日歌曲", 
                    "key": "V1001_TODAY_MUSIC", 
                    "sub_button": [ ]
                }, 
                {
                    "name": "菜单", 
                    "sub_button": [
                        {
                            "type": "view", 
                            "name": "搜索", 
                            "url": "http://www.soso.com/", 
                            "sub_button": [ ]
                        }, 
                        {
                            "type": "view", 
                            "name": "视频", 
                            "url": "http://v.qq.com/", 
                            "sub_button": [ ]
                        }, 
                        {
                            "type": "click", 
                            "name": "赞一下我们", 
                            "key": "V1001_GOOD", 
                            "sub_button": [ ]
                        }
                    ]
                }
            ], 
            "matchrule": {
                "group_id": 2, 
                "sex": 1, 
                "country": "中国", 
                "province": "广东", 
                "city": "广州", 
                "client_platform_type": 2
            }, 
            "menuid": 208396993
        }
    ]
}

删除菜单

接口说明:

http请求方式:GET
https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
正确返回消息:
{"errcode":0,"errmsg":"ok"}
错误返回消息同上

这里需要注意的是,该方式将删除整个菜单。

个性化菜单

为了帮助公众号实现灵活的业务运营,微信公众平台新增了个性化菜单接口,开发者可以通过该接口,让公众号的不同用户群体看到不一样的自定义菜单。该接口开放给已认证订阅号和已认证服务号。

开发者可以使用如下方式标志用户:

  1. 用户标签(开发者的业务需求可以借助用户标签来完成)
  2. 性别
  3. 手机操作系统地区(用户在微信客户端设置的地区)
  4. 语言(用户在微信客户端设置的语言)

使用个性化菜单需要有以下几点注意:

  1. 个性化菜单要求用户的微信客户端版本在iPhone6.2.2,Android 6.2.4以上,暂时不支持其他版本微信;
  2. 菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果;
  3. 普通公众号的个性化菜单的新增接口每日限制次数为2000次,删除接口也是2000次,测试个性化菜单匹配结果接口为20000次;
  4. 出于安全考虑,一个公众号的所有个性化菜单,最多只能设置为跳转到3个域名下的链接;
  5. 创建个性化菜单之前必须先创建默认菜单(默认菜单是指使用普通自定义菜单创建接口创建的菜单)。如果删除默认菜单,个性化菜单也会全部删除;
  6. 个性化菜单接口支持用户标签,请开发者注意,当用户身上的标签超过1个时,以最后打上的标签为匹配;

创建个性化菜单:

请求方式:POST(请使用https协议)
https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN
POST数据为JSON对象;
{
     "button":[
     {    
        "type":"click",
        "name":"今日歌曲",
         "key":"V1001_TODAY_MUSIC" },
    {     "name":"菜单",
        "sub_button":[
        {            
            "type":"view",
            "name":"搜索",
            "url":"http://www.soso.com/"},
            {
                         "type":"miniprogram",
                         "name":"wxa",
                         "url":"http://mp.weixin.qq.com",
                         "appid":"wx286b93c14bbf93aa",
                         "pagepath":"pages/lunar/index"
            },
             {
        "type":"click",
        "name":"赞一下我们",
        "key":"V1001_GOOD"
           }]
 }],
"matchrule":{
  "tag_id":"2",
  "sex":"1",
  "country":"中国",
  "province":"广东",
  "city":"广州",
  "client_platform_type":"2",
  "language":"zh_CN"
  }
}
正确返回消息:
{"menuid":"208379533"}——menuid即为该菜单的标记;可用于以后删除使用;

删除个性化菜单:

请求方式:POST(请使用https协议)
https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token=ACCESS_TOKEN
参数说明:
POST数据为JSON字符串
{"menuid":"208379533"}
正确返回:
{"errcode":0,"errmsg":"ok"}
错误返回:
通用

自定义菜单事件推送

注意,第3个到第8个的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。

click类型的消息推送:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[CLICK]]></Event>
<EventKey><![CDATA[EVENTKEY]]></EventKey>
</xml>

view类型的消息推送:
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[FromUser]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[VIEW]]></Event>
<EventKey><![CDATA[www.qq.com]]></EventKey>
<MenuId>MENUID</MenuId>//指菜单ID,如果是个性化菜单,则可以通过这个字段,知道是哪个规则的菜单被点击了。
</xml>

scancode_push类型的消息推送:
<xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
<CreateTime>1408090502</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[scancode_push]]></Event>
<EventKey><![CDATA[6]]></EventKey>
<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>
<ScanResult><![CDATA[1]]></ScanResult>
</ScanCodeInfo>
</xml>

scancode_waitmsg类型的消息推送:
<xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
<CreateTime>1408090606</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[scancode_waitmsg]]></Event>
<EventKey><![CDATA[6]]></EventKey>
<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>
<ScanResult><![CDATA[2]]></ScanResult>
</ScanCodeInfo>
</xml>

pic_sysphoto类型的消息推送:
<xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
<CreateTime>1408090651</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[pic_sysphoto]]></Event>
<EventKey><![CDATA[6]]></EventKey>
<SendPicsInfo><Count>1</Count>
<PicList><item><PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>
</item>
</PicList>
</SendPicsInfo>
</xml>

pic_photo_or_album类型的消息推送:
<xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
<CreateTime>1408090816</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[pic_photo_or_album]]></Event>
<EventKey><![CDATA[6]]></EventKey>
<SendPicsInfo><Count>1</Count>
<PicList><item><PicMd5Sum><![CDATA[5a75aaca956d97be686719218f275c6b]]></PicMd5Sum>
</item>
</PicList>
</SendPicsInfo>
</xml>

pic_weixin类型的消息推送:
<xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
<CreateTime>1408090816</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[pic_weixin]]></Event>
<EventKey><![CDATA[6]]></EventKey>
<SendPicsInfo><Count>1</Count>
<PicList><item><PicMd5Sum><![CDATA[5a75aaca956d97be686719218f275c6b]]></PicMd5Sum>
</item>
</PicList>
</SendPicsInfo>
</xml>

location_select类型的消息推送:
<xml><ToUserName><![CDATA[gh_e136c6e50636]]></ToUserName>
<FromUserName><![CDATA[oMgHVjngRipVsoxg6TuX3vz6glDg]]></FromUserName>
<CreateTime>1408091189</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Event><![CDATA[location_select]]></Event>
<EventKey><![CDATA[6]]></EventKey>
<SendLocationInfo><Location_X><![CDATA[23]]></Location_X>
<Location_Y><![CDATA[113]]></Location_Y>
<Scale><![CDATA[15]]></Scale>
<Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>
<Poiname><![CDATA[]]></Poiname>
</SendLocationInfo>
</xml>

用户管理

标签管理

开发者可以使用用户标签管理的相关接口,实现对公众号标签的管理;标签可以用于对用户的分类管理;

每个公众号可以创建100个标签;创建方式如下:

请求方式:POST(使用https协议);
请求地址:https://api.weixin.qq.com/cgi-bin/tags/create?access_token=ACCESS_TOKEN
POST数据格式:
{   "tag":{ "name" : "广东"//标签名长度不能超过30字节}}
返回结果:
{   "tag":{ "id":134,id "name":"广东"   } }//包含tag-id

获取公众号已创建的标签:

请求方式:GET(使用https协议) 
请求地址:https://api.weixin.qq.com/cgi-bin/tags/get?access_token=ACCESS_TOKEN
返回说明:
{   "tags":[{       "id":1,       "name":"每天一罐可乐星人",       "count":0 //此标签下粉丝数 },{   "id":2,   "name":"星标组",   "count":0 },{   "id":127,   "name":"广东",   "count":5 }   ] }

编辑标签:

请求方式:POST(请使用https协议)
请求地址:https://api.weixin.qq.com/cgi-bin/tags/update?access_token=ACCESS_TOKEN
POST数据:
{   "tag" : {     "id" : 134,     "name" : "广东人"   } }
返回说明:
正确返回:{   "errcode":0,   "errmsg":"ok" }
错误返回:详见错误返回码

删除标签:

请注意,当某个标签下的粉丝超过10w时,后台不可直接删除标签。此时,开发者可以对该标签下的openid列表,先进行取消标签的操作,直到粉丝数不超过10w后,才可直接删除该标签。

请求方式:POST(使用https协议) 
请求地址:https://api.weixin.qq.com/cgi-bin/tags/delete?access_token=ACCESS_TOKEN
POST数据:
{   "tag":{        "id" : 134   } }
返回说明:
正确返回:{   "errcode":0,   "errmsg":"ok" }
错误返回:详见错误返回码

获取标签下的粉丝列表:

请求方式:POST(请使用https协议) 
请求地址:https://api.weixin.qq.com/cgi-bin/user/tag/get?access_token=ACCESS_TOKEN
POST数据格式:JSON
{   "tagid" : 134,   "next_openid":""//第一个拉取的OPENID,不填默认从头开始拉取 }
返回说明:
{ 
    "count":2,//这次获取的粉丝数量   
    "data":{//粉丝列表
        "openid":[  
            "ocYxcuAEy30bX0NXmGn4ypqx3tI0",    
            "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"
        ]  
    },  
    "next_openid":"ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"//拉取列表最后一个用户的openid 
}

用户标签管理

标签功能支持为公众号用户进行打标签、取消标签等操作;该功能可以实现个性化菜单定制

批量为用户打标签

请求方式:POST(请使用https协议)
请求地址:https://api.weixin.qq.com/cgi-bin/tags/members/batchtagging?access_token=ACCESS_TOKEN
POST数据:
{   
    "openid_list" : [//粉丝列表    
        "ocYxcuAEy30bX0NXmGn4ypqx3tI0",    
        "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"],   
    "tagid" : 134 
}
返回说明:
{   
    "errcode":0,   
    "errmsg":"ok"
}

批量为用户取消标签

请求方式:POST(请使用https协议) 
请求地址:https://api.weixin.qq.com/cgi-bin/tags/members/batchuntagging?access_token=ACCESS_TOKEN
POST数据格式:JSON
{
    "openid_list" : [//粉丝列表     
        "ocYxcuAEy30bX0NXmGn4ypqx3tI0",     
        "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y"],   
    "tagid" : 134
}
返回说明:{"errcode":0, "errmsg":"ok"}

获取用户的标签列表

请求方式:POST(请使用https协议)
请求地址:https://api.weixin.qq.com/cgi-bin/tags/getidlist?access_token=ACCESS_TOKEN
POST数据格式:JSON
{   "openid" : "ocYxcuBt0mRugKZ7tGAHPnUaOW7Y" }
返回说明:{   "tagid_list":[//被置上的标签列表 134, 2   ] }

设置用户备注名

请求方式: POST(请使用https协议)
请求地址:https://api.weixin.qq.com/cgi-bin/user/info/updateremark?access_token=ACCESS_TOKEN
POST数据格式:JSON
POST数据例子:
{
    "openid":"oDF3iY9ffA-hqb2vVvbr7qxf6A0Q",
    "remark":"pangzi"//标签名
}
返回说明:{"errcode":0,"errmsg":"ok"}

获取用户基本信息

注意,这里获的用户基本信息是在关注者和公众号产生消息交互后,公众号可获得该用户的Open ID,之后在响应系统中,通过Open ID获的Union ID以及基本信息

请求方式: GET
请求地址:https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
返回说明:正常情况下,微信会返回下述JSON数据包给公众号
{
    "subscribe": 1, 
    "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M", 
    "nickname": "Band", 
    "sex": 1, 
    "language": "zh_CN", 
    "city": "广州", 
    "province": "广东", 
    "country": "中国", 
    "headimgurl":"http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
    "subscribe_time": 1382694957,
    "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
    "remark": "",
    "groupid": 0,
    "tagid_list":[128,2],
    "subscribe_scene": "ADD_SCENE_QR_CODE",
    "qr_scene": 98765,
    "qr_scene_str": ""
}

批量获得用户基本信息

请求方式: POST
请求地址:https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN
POST:JSON
{
    "user_list": [
        {
            "openid": "otvxTs4dckWG7imySrJd6jSi0CWE", 
            "lang": "zh_CN"
        }, 
        {
            "openid": "otvxTs_JZ6SEiP0imdhpi50fuSZg", 
            "lang": "zh_CN"
        }
    ]
}
返回说明:
{
   "user_info_list": [
       {
           "subscribe": 1, 
           "openid": "otvxTs4dckWG7imySrJd6jSi0CWE", 
           "nickname": "iWithery", 
           "sex": 1, 
           "language": "zh_CN", 
           "city": "揭阳", 
           "province": "广东", 
           "country": "中国", 

           "headimgurl": "http://thirdwx.qlogo.cn/mmopen/xbIQx1GRqdvyqkMMhEaGOX802l1CyqMJNgUzKP8MeAeHFicRDSnZH7FY4XB7p8XHXIf6uJA2SCunTPicGKezDC4saKISzRj3nz/0",

          "subscribe_time": 1434093047, 
           "unionid": "oR5GjjgEhCMJFyzaVZdrxZ2zRRF4", 
           "remark": "", 

           "groupid": 0,
           "tagid_list":[128,2],
           "subscribe_scene": "ADD_SCENE_QR_CODE",
           "qr_scene": 98765,
           "qr_scene_str": ""

      }, 
       {
           "subscribe": 0, 
           "openid": "otvxTs_JZ6SEiP0imdhpi50fuSZg"
       }
   ]
}

获取用户列表

公众号可通过本接口来获取帐号的关注者列表,关注者列表由一串OpenID(加密后的微信号,每个用户对每个公众号的OpenID是唯一的)组成。一次拉取调用最多拉取10000个关注者的OpenID,可以通过多次拉取的方式来满足需求。

请求方式: GET(请使用https协议)
请求地址:https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID
返回说明:
{
    "total":2,
    "count":2,
    "data":{
        "openid":["OPENID1","OPENID2"]
    },
    "next_openid":"NEXT_OPENID"
}

当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求。

具体而言,就是在调用接口时,将上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值。

消息管理

接收普通消息

当普通用户向公众号发送消息时,微信系统将POST消息的XML数据包到开发者填写的URL上;

注意事项:

  1. 微信服务器在5s内收不到响应并不会断掉连接,并且重新发起请求,总共重试3次;如果服务器无法保证在5s内做出响应,应当回复空串。
  2. 如果开发者需要在5s内对用户发送的消息做出回应,即使用发送消息->被回复消息接口向用户被动回复消息,那么需要选择对消息的加密方式,详情见 消息加密;

各种消息体结构(XML格式组织,可使用输入流的方式读取):

注意,首次出现的XML标签将给出注释,第二次出现则不再注释,该规则同样适用于后面的接收事件消息

  1. 文本消息

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>   //开发者微信号
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>     //用户的openid
    <CreateTime>1348831860</CreateTime>
    <MsgType>< ![CDATA[text] ]></MsgType>   //文本为text
    <Content>< ![CDATA[this is a test] ]></Content>
    <MsgId>1234567890123456</MsgId>     //64位整型
    </xml>
  2. 图片消息

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1348831860</CreateTime>
    <MsgType>< ![CDATA[image] ]></MsgType>  //图片为image
    <PicUrl>< ![CDATA[this is a url] ]></PicUrl>
    <MediaId>< ![CDATA[media_id] ]></MediaId>   //可使用图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
    <MsgId>1234567890123456</MsgId>
    </xml>
  3. 语音消息

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1357290913</CreateTime>
    <MsgType>< ![CDATA[voice] ]></MsgType>  //语音为voice
    <MediaId>< ![CDATA[media_id] ]></MediaId>
    <Format>< ![CDATA[Format] ]></Format>   //语音格式,如amr,speex等
    <MsgId>1234567890123456</MsgId>
    <Recognition>< ![CDATA[腾讯微信团队] ]></Recognition>
    </xml>

    这里需要注意的是,如果开启了语音识别,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,增加一个Recongnition字段标志识别结果;

  4. 视频消息

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1357290913</CreateTime>
    <MsgType>< ![CDATA[video] ]></MsgType>  //视频为video
    <MediaId>< ![CDATA[media_id] ]></MediaId>   //可使用图片消息媒体id,可以调用多媒体文件下载接口拉取数据。
    <ThumbMediaId>< ![CDATA[thumb_media_id] ]></ThumbMediaId>   //视频消息缩略图的媒体id,可以调用多媒体文件下载接口拉取数据。
    <MsgId>1234567890123456</MsgId></xml>
  5. 小视频消息

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1357290913</CreateTime>
    <MsgType>< ![CDATA[shortvideo] ]></MsgType>     //小视频为shortvideo
    <MediaId>< ![CDATA[media_id] ]></MediaId>
    <ThumbMediaId>< ![CDATA[thumb_media_id] ]></ThumbMediaId>
    <MsgId>1234567890123456</MsgId>
    </xml>
  6. 地理位置消息

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1351776360</CreateTime>
    <MsgType>< ![CDATA[location] ]></MsgType>   //地理位置为 location
    <Location_X>23.134521</Location_X>  // 地理纬度
    <Location_Y>113.358803</Location_Y> // 地理经度
    <Scale>20</Scale>   //地图缩放大小
    <Label>< ![CDATA[位置信息] ]></Label>   //地理位置信息
    <MsgId>1234567890123456</MsgId>
    </xml>
    
  7. 链接消息

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>1351776360</CreateTime>
    <MsgType>< ![CDATA[link] ]></MsgType>   //链接消息为 link
    <Title>< ![CDATA[公众平台官网链接] ]></Title>   //标题
    <Description>< ![CDATA[公众平台官网链接] ]></Description>   //描述
    <Url>< ![CDATA[url] ]></Url>    //消息链接
    <MsgId>1234567890123456</MsgId>
    </xml>
    

接收事件消息

在微信用户和公众号产生交互的过程中,用户的某些操作会使得微信系统通过事件推送的形式通知响应系统,从而开发者可以获取到该信息。其中,某些事件推送在发生后,是允许开发者回复用户的,某些则不允许,详细内容如下:

  1. 关注/取消关注事件
  2. 扫描带参数二维码事件
  3. 上报地理位置事件
  4. 自定义菜单事件
  5. 点击菜单拉取消息的事件
  6. 点击菜单跳转链接时的事件

各种事件介绍:

  1. 关注/取消关注事件

    用户在关注与取消关注公众号时,微信系统会把这个事件推送到响应系统,方便开发者给用户下发欢迎消息或者做帐号的解绑。为保护用户数据隐私,开发者收到用户取消关注事件时需要删除该用户的所有信息。

    推送XML数据包示例:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>   //开发者微信号
    <FromUserName>< ![CDATA[FromUser] ]></FromUserName>     //用户的OennID
    <CreateTime>123456789</CreateTime>  //创建时间,int整型
    <MsgType>< ![CDATA[event] ]></MsgType>
    <Event> //消息类型为event< ![CDATA[subscribe] ]></Event> //事件类型,subscribe(订阅)、unsubscribe(取消订阅)
    </xml>
    
  2. 扫描带参数二维码事件:

    用户扫描带场景值二维码时,可能推送以下两种事件:

    1. 如果用户还未关注公众号,则用户可以关注公众号,关注后微信系统会将带场景值关注事件推送给响应系统。
    2. 如果用户已经关注公众号,则微信系统会将带场景值的扫描事件推送响应系统。

    推送XML数据包示例:

    用户未关注时,进行关注后的事件推送
    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[FromUser] ]></FromUserName>
    <CreateTime>123456789</CreateTime>
    <MsgType>< ![CDATA[event] ]></MsgType>      //消息类型为event
    <Event>< ![CDATA[subscribe] ]></Event>  //事件类型,subscribe
    <EventKey>< ![CDATA[qrscene_123123] ]></EventKey>   //事件KEY值,qrscene_为前缀,后面为二维码的参数值
    <Ticket>< ![CDATA[TICKET] ]></Ticket>   //二维码的ticket,可用来换取二维码图片
    </xml>
    
    用户已关注时的事件推送
    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName> 
    <FromUserName>< ![CDATA[FromUser] ]></FromUserName> 
    <CreateTime>123456789</CreateTime> 
    <MsgType>< ![CDATA[event] ]></MsgType>
       <Event>< ![CDATA[SCAN] ]></Event>
       <EventKey>< ![CDATA[SCENE_VALUE] ]></EventKey>   //创建二维码是的scene_id
       <Ticket>< ![CDATA[TICKET] ]></Ticket>    //二维码的ticket,可用来换取图片
    </xml>
    
  3. 上报地理位置事件

    用户同意上报地理位置后,每次进入公众号会话时,都会进入上报地理位置,或在进入会话后每5秒报一次地理位置。上报地理位置时,微信系统将上报地理位置事件推送到响应系统;

    推送XML数据包示例:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>123456789</CreateTime>
    <MsgType>< ![CDATA[event] ]></MsgType>
    <Event>< ![CDATA[LOCATION] ]></Event>
    <Latitude>23.137466</Latitude>  //维度
    <Longitude>113.352425</Longitude>   //经度
    <Precision>119.385040</Precision>   //地理位置精度
    </xml>
    
  4. 自定义菜单事件

    用户点击自定义菜单后,微信系统会把点击事件推送给响应系统,点击菜单弹出子菜单,不会产生上报。

    推送XML数据包示例:

    点击菜单拉取消息时的事件推送
    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[FromUser] ]></FromUserName>
    <CreateTime>123456789</CreateTime>
    <MsgType>< ![CDATA[event] ]></MsgType>
    <Event>< ![CDATA[CLICK] ]></Event>  //事件类型为CLICK
    <EventKey>< ![CDATA[EVENTKEY] ]></EventKey> //事件KEY值,与自定义菜单接口中KEY值对应
    </xml>
    
    点击菜单跳转链接时的事件推送
    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[FromUser] ]></FromUserName>
    <CreateTime>123456789</CreateTime>
    <MsgType>< ![CDATA[event] ]></MsgType>  
    <Event>< ![CDATA[VIEW] ]></Event>   //事件类型为 VIEW
    <EventKey>< ![CDATA[www.qq.com] ]></EventKey>   //事件的KEY值,设置的跳转URL
    </xml>
    

被动回复用户消息

当用户发送消息给公众号时,或某些特定的用户操作引发的事件推送时,微信系统会将一个POST请求发送到响应系统,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应,这种方式称为被动回复用户消息。

现支持回复文本、图片、图文、语音、视频、音乐。

发送被动响应消息其实并不是一种接口,而是对微信系统发过来消息的一次回复,只是这次回复将发送到用户。

被动回复消息的数据格式:

注意:

  1. 回复图片(不支持gif动图)等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器,可以使用素材管理中的临时素材,也可以使用永久素材。

  2. 一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:

    1. 开发者在5秒内未回复任何内容;
    2. 开发者回复了异常数据,比如JSON数据等;
  3. 回复文本消息

    XML格式数据:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>   //用户Open id
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName> //开发者 微信号;这两者都可以从响应系统收到的消息里获得
       <CreateTime>12345678</CreateTime>
       <MsgType>< ![CDATA[text] ]></MsgType>    //消息类型为:text
       <Content>< ![CDATA[你好] ]></Content>
    </xml>
    
  4. 回复图片消息

    XML格式数据:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType>< ![CDATA[image] ]></MsgType>  //消息类型为:image
    <Image>
        <MediaId>< ![CDATA[media_id] ]></MediaId>//通过素材管理中的接口上传多媒体文件,得到的id。
    </Image>
    </xml>
    
  5. 回复语音消息

    XML格式数据:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType>< ![CDATA[voice] ]></MsgType>  //消息类型为:voice
    <Voice>
        <MediaId>< ![CDATA[media_id] ]></MediaId>
    </Voice>
    </xml>
    
  6. 回复视频消息

    XML格式数据:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType>< ![CDATA[video] ]></MsgType>  //消息类型为:video
    <Video>
        <MediaId>< ![CDATA[media_id] ]></MediaId>
        <Title>< ![CDATA[title] ]></Title>  //视频的标题
        <Description>< ![CDATA[description] ]></Description>    //视频的描述
    </Video>
    </xml>
    
  7. 回复音乐消息

    XML格式数据:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType>< ![CDATA[music] ]></MsgType>
    <Music>
        <Title>< ![CDATA[TITLE] ]></Title>
        <Description>< ![CDATA[DESCRIPTION] ]></Description>
        <MusicUrl>< ![CDATA[MUSIC_Url] ]></MusicUrl>
        <HQMusicUrl>< ![CDATA[HQ_MUSIC_Url] ]></HQMusicUrl>
        <ThumbMediaId>< ![CDATA[media_id] ]></ThumbMediaId>
    </Music>
    </xml>
    
  8. 回复图文消息

    XML格式数据:

    <xml>
    <ToUserName>< ![CDATA[toUser] ]></ToUserName>
    <FromUserName>< ![CDATA[fromUser] ]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType>< ![CDATA[news] ]></MsgType>
    <ArticleCount>2</ArticleCount>
    <Articles>
        <item>
            <Title>< ![CDATA[title1] ]></Title>
            <Description>< ![CDATA[description1] ]></Description>
            <PicUrl>< ![CDATA[picurl] ]></PicUrl>
            <Url>< ![CDATA[url] ]></Url>
        </item>
        <item>
            <Title>< ![CDATA[title] ]></Title>
            <Description>< ![CDATA[description] ]></Description>
            <PicUrl>< ![CDATA[picurl] ]></PicUrl>
            <Url>< ![CDATA[url] ]></Url>
        </item>
    </Articles>
    </xml>
    

主动发送消息

主动发送消息是通过模板消息实现的,模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。

为了发送模板消息,需要首先设置公众号所属的行业,之后公众号则只能使用该行业内的模板来发送模板消息;设置行业可以通过微信公众平台后台来完成,每月可修改一次;也可以通过接口调用的方式来修改所属行业;

定义模板消息时需要注意的地方:

  1. 模板消息调用时主要需要模板ID和模板中各参数的赋值内容;
  2. 模板中参数内容必须以”.DATA”结尾,否则视为保留字;
  3. 模板保留符号”{{ }}”;
  4. 详情见:获得已添加到微信公众号里的所有模板列表;

设置所属行业:

请求方式: POST
请求地址:https://api.weixin.qq.com/cgi-bin/template/api_set_industry?access_token=ACCESS_TOKEN
POST数据格式:
{"industry_id1":"1","industry_id2":"4"}

获得模板ID:

该过程可在公众号后台完成,同时提供接口:

请求方式: POST
请求地址:https://api.weixin.qq.com/cgi-bin/template/api_add_template?access_token=ACCESS_TOKEN
POST数据格式:
{"template_id_short":"TM00015"}
正确返回消息说明:JSON
{"errcode":0,"errmsg":"ok","template_id":"Doclyl5uP7Aciu-qZ7mJNPtWkbkYnWBWVja26EGbNyk"}
错误返回消息说明:
错误码通用。

获取已添加到微信公众号里的所有模板列表:

请求方式:GET
请求地址:https//api.weixin.qq.com/cgi-bin/template/get_all_private_template?access_token=ACCESS_TOKEN
返回结果说明:
{    
 "template_list": [{
      "template_id": "iPk5sOIt5X_flOVKn5GrTFpncEYTojx6ddbt8WYoV5s",
      "title": "领取奖金提醒",
      "primary_industry": "IT科技",
      "deputy_industry": "互联网|电子商务",
      "content": "{ {result.DATA} }\n\n领奖金额:{ {withdrawMoney.DATA} }\n领奖  时间:{ {withdrawTime.DATA} }\n银行信息:{ {cardInfo.DATA} }\n到账时间:  { {arrivedTime.DATA} }\n{ {remark.DATA} }",
      "example": "您已提交领奖申请\n\n领奖金额:xxxx元\n领奖时间:2013-10-10 12:22:22\n银行信息:xx银行(尾号xxxx)\n到账时间:预计xxxxxxx\n\n预计将于xxxx到达您的银行卡"
   }]
}

删除模板:

该过程可在公众号后台完成,同时提供接口:

请求方式:POST
请求地址:https://api.weixin.qq.com/cgi-bin/template/del_private_template?access_token=ACCESS_TOKEN
POST数据格式:
{"template_id" : "Dyvp3-Ff0cnail_CDSzk1fIc6-9lOkxsQE7exTJbwUE"}
正确返回消息说明:JSON
错误返回消息说明:
{"errcode" : 0,"errmsg" : "ok"}
错误码通用。

发送模板消息:

请求方式: POST
请求地址:https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
POST数据格式:
{
    "touser":"OPENID",
    "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
    "url":"http://weixin.qq.com/download",  
     "miniprogram":{
        "appid":"xiaochengxuappid12345",
        "pagepath":"index?foo=bar"
     },
     "data":{
        "first": {
            "value":"恭喜你购买成功!",
            "color":"#173177"
        },
        "keyword1":{
            "value":"巧克力",
            "color":"#173177"
        },
        "keyword2": {
            "value":"39.8元",
            "color":"#173177"
        },
        "keyword3": {
            "value":"2014年9月22日",
            "color":"#173177"
        },
        "remark":{
            "value":"欢迎再次购买!",
            "color":"#173177"
        }
    }
}
正确返回消息格式:
{"errcode":0,"errmsg":"ok","msgid":200228332}

事件推送:

在模版消息发送任务完成后,微信系统会将是否送达成功作为通知,发送到响应系统。

送达成功时,推送的XML如下:
<xml>
    <ToUserName>< ![CDATA[gh_7f083739789a] ]></ToUserName>
    <FromUserName>< ![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8] ]></FromUserName>
    <CreateTime>1395658920</CreateTime>
    <MsgType>< ![CDATA[event] ]></MsgType>
    <Event>< ![CDATA[TEMPLATESENDJOBFINISH] ]></Event>
    <MsgID>200163836</MsgID>
    <Status>< ![CDATA[success] ]></Status>
</xml>

没有送达时,推送的XML如下:
<xml>
    <ToUserName>< ![CDATA[gh_7f083739789a] ]></ToUserName>
    <FromUserName>< ![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8] ]></FromUserName>
    <CreateTime>1395658984</CreateTime>
    <MsgType>< ![CDATA[event] ]></MsgType>
    <Event>< ![CDATA[TEMPLATESENDJOBFINISH] ]></Event>
    <MsgID>200163840</MsgID>
    <Status>< ![CDATA[failed:user block] ]></Status>    //failed: system failed——其他原因;failed:user block——用户拒绝接收该公众号的消息
</xml>

消息加密

公众号消息加解密是为了进一步加强公众号安全保障,提供的新机制。公众账号主动调用API的情况不受影响。只有被动回复用户的消息时,才需要进行消息加解密。消息加解密方式:

  1. 明文模式:维持现有模式,没有适配加解密新特性,消息体明文收发,默认设置为明文模式;
  2. 兼容模式:公众平台发送消息内容将同时包括明文和密文,消息包长度增加到原来的3倍左右;公众号回复明文或密文均可,不影响现有消息收发;开发者可在此模式下进行调试;
  3. 安全模式(推荐):公众平台发送消息体的内容只含有密文,公众账号回复的消息体也为密文,建议开发者在调试成功后使用此模式收发消息

启用加解密功能(即选择兼容模式或安全模式)后,微信系统在向响应系统推送消息时,URL将新增加两个参数(加密类型和消息体签名),并以此来体现新功能。加密算法采用AES。具体方案见该模块代码实现。

获取微信系统服务器地址

出于安全等考虑,如需要获知微信服务器的IP地址列表,可以通过该接口获得微信服务器IP地址列表或者IP网段信息。

请求方式: GET
请求地址:https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=ACCESS_TOKEN
返回消息:JSON格式
{"ip_list":["127.0.0.1","127.0.0.2","101.226.103.0/25"]}

客服消息及管理

当用户和公众号产生特定动作的交互时(具体动作列表请见下方说明),微信系统将会把消息数据推送给响应系统,响应系统可以在一段时间内(目前修改为48小时)调用客服接口,通过POST一个JSON数据包来发送消息给普通用户。此接口主要用于客服等有人工消息处理环节的功能,方便开发者为用户提供更加优质的服务。

目前允许的动作列表如下(公众平台会根据运营情况更新该列表,不同动作触发后,允许的客服接口下发消息条数不同,下发条数达到上限后,会遇到错误返回码,具体请见返回码说明页):

  1. 用户发送信息
  2. 点击自定义菜单(仅有点击推事件、扫码推事件、扫码推事件且弹出“消息接收中”提示框这3种菜单类型将会触发客服接口)
  3. 关注公众号
  4. 扫描二维码
  5. 支付成功
  6. 用户维权

客服账号管理:

请注意,必须先在公众平台官网为公众号设置微信号后才能使用该能力。

  1. 添加客服账号

    请求方式: POST
    请求地址:https://api.weixin.qq.com/customservice/kfaccount/add?access_token=ACCESS_TOKEN
    POST数据示例如下:
    {
        "kf_account" : "test1@test",
        "nickname" : "客服1",
        "password" : "pswmd5",
    }
    返回说明(正确时的JSON返回结果):
    {"errcode" : 0,"errmsg" : "ok"}
    返回错误码是通用的
    
  2. 删除客服账号

    请求方式: GET
    请求地址:https://api.weixin.qq.com/customservice/kfaccount/del?access_token=ACCESS_TOKEN
    POST数据示例如下:
    {
        "kf_account" : "test1@test",
        "nickname" : "客服1",
        "password" : "pswmd5",
    }
    返回说明(正确时的JSON返回结果):
    {"errcode" : 0,"errmsg" : "ok"}
    返回错误码是通用的
    
  3. 修改客服账号

    请求方式: POST
    请求地址:https://api.weixin.qq.com/customservice/kfaccount/update?access_token=ACCESS_TOKEN
    POST数据示例如下:
    {
        "kf_account" : "test1@test",
        "nickname" : "客服1",
        "password" : "pswmd5",
    }
    返回说明(正确时的JSON返回结果):
    {"errcode" : 0,"errmsg" : "ok"}
    返回错误码是通用的
    

设置客服账号头像

开发者可调用该接口来上传图片作为客服人员的头像,头像图片文件必须是jpg格式,推荐使用640*640大小的图片以达到最佳效果。该接口调用请求如下:

请求方式: POST/FORM
请求地址:http://api.weixin.qq.com/customservice/kfaccount/uploadheadimg?access_token=ACCESS_TOKEN&kf_account=KFACCOUNT
这里需要注意的是,官方文档中提到的是使用curl工具POST一个多媒体文件;这里我想只要通过代码将文件提交到上述地址就OK,因为curl是一个命令行工具,网上有在php中使用curl的,但是对Java的支持很惨淡,这一部分详见代码验证及图示。

获取所有客服账号

请求方式: GET
请求地址:https://api.weixin.qq.com/cgi-bin/customservice/getkflist?access_token=ACCESS_TOKEN
返回数据:
{
    "kf_list": [
        {
            "kf_account": "test1@test", 
            "kf_nick": "ntest1", 
            "kf_id": "1001" //这里需要注意的是,kf_id是第一次在这里出现,创建的时候并没有返回该字段;
            "kf_headimgurl": " http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjfUS8Ym0GSaLic0FD3vN0V8PILcibEGb2fPfEOmw/0"
        }, 
        {
            "kf_account": "test2@test", 
            "kf_nick": "ntest2", 
            "kf_id": "1002"
            "kf_headimgurl": " http://mmbiz.qpic.cn/mmbiz/4whpV1VZl2iccsvYbHvnphkyGtnvjfUS8Ym0GSaLic0FD3vN0V8PILcibEGb2fPfEOmw /0"
        }
    ]
}

客服接口-发送消息

请求方式: POST
请求地址:https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=ACCESS_TOKEN
各消息类型所需的JSON数据包如下:
文本消息:
{
    "touser":"OPENID",
    "msgtype":"text",
    "text":
    {
         "content":"Hello World"
    }
}
发送文本消息时,文本内容中可以携带跳转小程序的文字链:<a href="http://www.qq.com" data-miniprogram-appid="appid" data-miniprogram-path="pages/index/index">点击跳小程序</a>
参数说明:
1.data-miniprogram-appid 项,填写小程序appid,则表示该链接跳小程序;
2.data-miniprogram-path项,填写小程序路径,路径与app.json中保持一致,可带参数;
3.对于不支持data-miniprogram-appid 项的客户端版本,如果有herf项,则仍然保持跳href中的网页链接;

注意,data-miniprogram-appid对应的小程序必须与公众号有绑定关系。

发送图片消息:
{
    "touser":"OPENID",
    "msgtype":"image",
    "image":
    {
      "media_id":"MEDIA_ID"
    }
}

发送语音消息:
{
    "touser":"OPENID",
    "msgtype":"voice",
    "voice":
    {
      "media_id":"MEDIA_ID"
    }
}

发送视频消息:
{
    "touser":"OPENID",
    "msgtype":"video",
    "video":
    {
      "media_id":"MEDIA_ID",
      "thumb_media_id":"MEDIA_ID",
      "title":"TITLE",
      "description":"DESCRIPTION"
    }
}

发送音乐消息:
{
    "touser":"OPENID",
    "msgtype":"music",
    "music":
    {
      "title":"MUSIC_TITLE",
      "description":"MUSIC_DESCRIPTION",
      "musicurl":"MUSIC_URL",
      "hqmusicurl":"HQ_MUSIC_URL",
      "thumb_media_id":"THUMB_MEDIA_ID" 
    }
}

发送图文消息(点击跳转到外链) 图文消息条数限制在8条以内,注意,如果图文数超过8,则将会无响应。
{
    "touser":"OPENID",
    "msgtype":"news",
    "news":{
        "articles": [
         {
             "title":"Happy Day",
             "description":"Is Really A Happy Day",
             "url":"URL",
             "picurl":"PIC_URL"
         },
         {
             "title":"Happy Day",
             "description":"Is Really A Happy Day",
             "url":"URL",
             "picurl":"PIC_URL"
         }
         ]
    }
}

发送图文消息:
{
    "touser":"OPENID",
    "msgtype":"mpnews",
    "mpnews":
    {
         "media_id":"MEDIA_ID"
    }
}

发送卡券:
{
  "touser":"OPENID", 
  "msgtype":"wxcard",
  "wxcard":{              
       "card_id":"123dsdajkasd231jhksad"        
   },
}
发送小程序卡片:
{
    "touser":"OPENID",
    "msgtype":"miniprogrampage",
    "miniprogrampage":
    {
        "title":"title",
        "appid":"appid",
        "pagepath":"pagepath",
        "thumb_media_id":"thumb_media_id"
    }
}

微信网页开发

网页授权获取用户基本信息

用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑。

这里需要注意的是同用户管理中的获取用户基本信息的区别:用户管理是在响应系统的完成的;而用户授权是在业务系统中完成的;两者工作的环境也是不同的,所以请求接口是不同的:第三方授权是在公众号内通过微信客户端进入网页时发生,而用户管理是公众号内部的管理行为;

使用流程:

  1. 在微信公众号请求用户网页授权之前,开发者需要先到公众平台官网中的“开发 - 接口权限 - 网页服务 - 网页帐号 - 网页授权获取用户基本信息”的配置选项中,修改授权回调域名。
  2. 授权回调域名配置规范为全域名。配置后,该域名下的所有网页都可以进行OAuth2.0鉴权。

两种请求模式:

  1. 以snsapi_base为scope发起的网页授权,用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务系统的入口);

  2. 以snsapi_userinfo为scope发起的网页授权,用来获取用户的基本信息的。这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。

    注意:用户管理类接口中的“获取用户基本信息接口”,是在用户和公众号产生消息交互或关注后事件推送后,才能根据用户OpenID来获取用户基本信息。该接口以及包括其他微信接口,都是需要该用户(即openid)关注了公众号后,才能调用成功的。

在OAuth2.0用户授权机制下,存在一个反应用户是否同意授权的标记,该标记在OAuth2.0的环境下称为:access_token。这和响应系统用于请求微信接口时使用的access_token是不一样的,但是它们的性质是相同的;

特殊环境下的静默授权:

  1. 上面已经提到,对于以snsapi_base为scope的网页授权,就静默授权的,用户无感知;
  2. 对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scope为snsapi_userinfo,也是静默授权,用户无感知。

具体而言,网页授权流程分为四步:

  1. 引导用户进入授权页面同意授权,获取code

    请求地址:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
    参数说明:APPID/REDIRECT_URI/SCOPE/StATE等为变量,其余为常量;参数顺序不可变;
    

    如果用户同意授权,页面将跳转至 REDIRECT_URI/?code=CODE&state=STATE。 code说明 : code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

  2. 通过code换取网页授权access_token(与基础支持中的access_token不同)

    请求地址:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
    参数说明:APPID/SECRET/CODE等为变量,其余为常量;参数顺序可变;
    返回数据:JSON
    { 
    "access_token":"ACCESS_TOKEN",//    网页授权接口调用凭证,注意:此access_token与基础支持的access_token不同
    "expires_in":7200,
    "refresh_token":"REFRESH_TOKEN",//用户刷新access_token
    "openid":"OPENID",
    "scope":"SCOPE"
    }
    

    注意:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。即当前请求是可以通过客户端进行的。

    另外,此时已经获得open id,即如果不需要使用union id 的话,网页授权到此结束;

  3. 如果需要,开发者可以刷新网页授权access_token,避免过期

    请求地址:https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
    参数说明:APPID/REFRESH_TOKEN为变量,REFRESH_TOKEN即为第二步获得数据
    
  4. 通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

    请求方式:GET
    请求地址:https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
    参数说明:ACCESS_TOKEN即为第二步获得网页授权数据;OPENID一样;
    返回数据说明:JSON
    {
    "openid":" OPENID",
    " nickname": NICKNAME,
    "sex":"1",
    "province":"PROVINCE"
    "city":"CITY",
    "country":"COUNTRY",
    "headimgurl": "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
    "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
    "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    }
    

    整体来看,App Secret作为秘密数据,其获取也应该通过业务系统的验证以检查正在请求App Secret的网页是不是友军;

微信JS-SDK的功能

JS-SDK为第三方网页在微信客户端内使用本地资源提供JS封装的接口;这里不涉及具体API的使用,仅介绍JS-SDK的引入、调用接口权限的验证配置。

引入JS文件:

同普通JS文件。

权限验证:

所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用,同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用,目前Android微信客户端不支持pushState的H5新特性,所以使用pushState来实现web app的页面会导致签名失败,此问题会在Android6.2中修复。

wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,签名算法见后专门模块
    jsApiList: [] // 必填,需要使用的JS接口列表
});

wx.ready(function(){
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});

wx.error(function(res){
    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
});

所有接口通过wx对象(也可使用jWeixin对象)来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:

  1. success:执行成功时的回调函数;
  2. fail:调用接口失败时执行的回调函数;
  3. complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。
  4. cancel:用户点击取消时的回调函数,仅部分有用户取消操作的api才会用到。
  5. trigger: 监听Menu中的按钮点击时触发的方法,该方法仅支持Menu中的相关接口。

以上几个函数都带有一个参数,类型为对象,其中除了每个接口本身返回的数据之外,还有一个通用属性errMsg,其值格式如下:

  1. 调用成功时:”xxx:ok” ,其中xxx为调用的接口名
  2. 用户取消时:”xxx:cancel”,其中xxx为调用的接口名
  3. 调用失败时:其值为具体错误信息

签名算法

生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。 开发者必须在自己的服务全局缓存jsapi_ticket 。

生成签名的流程:

  1. 获得access_token:具体见上文目录;

  2. 用第一步拿到的access_token获得jsapi_ticket

    请求方法:GET
    请求地址:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
    返回数据说明:JSON
    {
    "errcode":0,
    "errmsg":"ok",
    "ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
    "expires_in":7200
    }
    
  3. 签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。 sha1加密后的结果即为signature;

猜你喜欢

转载自blog.csdn.net/slx3320612540/article/details/81267605