Better

Ethan的博客,欢迎访问交流

微信公众号开发入门

由于ionic的牛逼,一套代码可以在三端同时上线,虽然目前在微信端体验并不是很好,比如加载时间过长(有优化方案),后退导致路由参数的问题(待研究完美方案),但对于初创型公司来说,这是快速迭代,节约成本的一种优秀解决方案。本以为公司在这一块只是浅尝辄止,谁知越做越全,碰到的问题就多了,这里总结一下微信的文档概要,对于能实现什么功能心中有数,同时总结一些容易理解错误的概念。

概述

开发准备

  1. 概念区分:微信公众平台开发是指为微信公众号进行业务开发,微信开放平台是指第三方平台(为各行各业公众号运营者提供服务)的开发。
  2. 测试号申请系统
  3. 接口调试工具来在线调试某些接口
  4. 接口调用频次限制
    • 公众号调用接口并不是无限制的。为了防止公众号的程序错误而引发微信服务器负载异常,默认情况下,每个公众号调用接口都不能超过一定限制,当超过一定限制时,调用对应接口会收到错误返回码45009
    • 开发者可以登录微信公众平台,在帐号后台开发者中心接口权限模板查看帐号各接口当前的日调用上限和实时调用量,对于认证帐号可以对实时调用量清零,每个帐号每月共10次清零操作机会
    • 具体频率
  5. 通过接口调用的返回码,以及报警排查指引来发现和解决问题
    • 微信公众平台已对外开放接口报警,当微信服务器向开发者推送消息失败次数达到预定阈值时,会将报警消息发送到指定微信报警群中(设置方式:公众平台->开发-运维中心->接口报警)
  6. 公众平台以access_token为接口调用凭据,来调用接口,所有接口的调用需要先获取access_token,access_token在2小时内有效,过期需要重新获取,但1天内获取次数有限,开发者需自行存储

通过上述的准备描述以及自己使用经验,有几个问题在这里着重声明:

  1. 如果直接在微信官方公众号中配置自己的回调服务器,会导致微信官方提供的运营功能失效,比如自定义菜单等,那么两者能够兼得的吗?现在看来答案是可以的,可以去微信开放平台开发第三方平台,然后通过公众号授权的方式,这样微信的回调同样会被转发到自己服务器,同时还不影响微信运营。
  2. 对于用缓存的需要更新的共享资源需要注意多线程的并发问题,比如access_token,ticket等,需要加锁保证安全,否则在高并发的情况下,极有可能出现问题。

安全性

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

用户识别

为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号、移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定后,一个用户虽然对多个公众号和应用有多个不同的OpenID,但他对所有这些同一开放平台账号下的公众号和应用,只有一个UnionID,可以在用户管理-获取用户基本信息(UnionID机制)文档了解详情。

微信服务

微信公众号能提供哪些服务呢?这是了解微信公众号能帮助我们做什么的关键!

  1. 公众号消息会话

    • 群发消息:有频率限制(订阅号为每天1次,服务号为每月4次),向用户群发消息,包括文字消息、图文消息、图片、视频、语音等。
    • 被动回复消息:在用户给公众号发消息后,公众号可以在5秒内做出回复,可以回复一个消息,也可以回复命令告诉微信服务器这条消息暂不回复。
    • 客服消息:在用户给公众号发消息后的48小时内,公众号可以给用户发送不限数量的消息,主要用于客服场景。
    • 模板消息:在需要对用户发送服务通知(如刷卡提醒、服务预约成功通知等)时,公众号可以用特定内容模板,主动向用户发送消息。
  2. 公众号内网页

    • 网页授权获取用户基本信息,分为静默授权(只能获取OpenID,设置为snsapi_base)和用户同意(获取基本信息,设置为snsapi_userinfo)
    • 微信JS-SDK:是开发者在网页上通过JavaScript代码使用微信原生功能的工具包,开发者可以使用它在网页上录制和播放微信语音、监听微信分享、上传手机本地图片、拍照等许多能力。

Token的使用和区别

之前一直搞不懂网页授权和基础授权的区别,容易弄混,今日重新看微信公众号的WIKI,思路清晰多了!

  1. 验证开发者服务器token
    • Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。
  2. 网页授权access_token
    • 用来得到用户的基本信息,微信会重定向在菜单URL中配置的URL参数,同时附带code参数,用code参数请求网页授权aceess_token,每日次数无限制,过期时间7200s。
    • 如果过期使用刷新access_token的API进行重新获取(刷新接口无次数限制)。
    • 网页授权access_token 只能获取到一个微信用户信息,是与微信用户一对一的关系。
    • 微信网页授权是通过OAuth2.0机制实现的,在用户授权给公众号后,公众号可以获取到一个网页授权特有的接口调用凭证(网页授权access_token),通过网页授权access_token可以进行授权后接口调用,如获取用户基本信息。
  3. 基础授权access_token
    • 其他微信接口,需要通过基础支持中的“获取access_token”接口来获取到的普通access_token调用。目前每日限制2000次,有效期7200s。
    • 刷新基础授权需要调用接口重新获取。
    • 基础支持的access_token,在有效期内就可以使用access_token和openId 获取微信用户信息。
    • 建议公众号开发者使用中控服务器统一获取和刷新Access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务;
    • 目前Access_token的有效期通过返回的expire_in来传达,目前是7200秒之内的值。中控服务器需要根据这个有效时间提前去刷新新access_token。在刷新过程中,中控服务器对外输出的依然是老access_token,此时公众平台后台会保证在刷新短时间内,新老access_token都可用,这保证了第三方业务的平滑过渡;
    • Access_token的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新access_token的接口,这样便于业务服务器在API调用获知access_token已超时的情况下,可以触发access_token的刷新流程。

入门开发

微信网页授权

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

两种scope的区别

  1. 以snsapi_base为scope发起的网页授权,是用来获取进入页面的用户的openid的,并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页(往往是业务页面)
  2. 以snsapi_userinfo为scope发起的网页授权,是用来获取用户的基本信息的。但这种授权需要用户手动同意,并且由于用户同意过,所以无须关注,就可在授权后获取该用户的基本信息。

静默授权

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

网页授权步骤

  1. 引导用户进入授权页面同意授权,获取code
  2. 通过code换取网页授权access_token(与基础支持中的access_token不同)
  3. 如果需要,开发者可以刷新网页授权access_token,避免过期
  4. 通过网页授权access_token和openid获取用户基本信息(支持UnionID机制)

JS-SDK使用

微信JS-SDK是微信公众平台面向网页开发者提供的基于微信内的网页开发工具包。

通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。

使用步骤:

  1. 绑定域名,填写JS接口安全域名
  2. 引入JS文件
  3. 通过config接口注入权限验证配置
  4. 所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用)
  5. 通过ready接口处理成功验证
    • config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
  6. 通过error接口处理失败验证

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

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

JS-SDK使用权限签名算法

  1. 生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket
  2. 签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
  3. 注意事项
    1. 签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
    2. 签名用的url必须是调用JS接口页面的完整URL。
    3. 出于安全考虑,开发者必须在服务器端实现签名的逻辑。

更多JS-SDK能实现的功能:JS-SDK

深入开发

在这里不做深入记录,有开发需要时自行查阅。

  1. 自定义菜单
  2. 消息关系
  3. 素材管理
  4. 用户管理
  5. 账号管理
  6. 数据统计
  7. 微信卡券
  8. 微信门店
  9. 微信小店
  10. 微信设备
  11. 微信摇一摇
  12. ...

看wiki真的是索然无味的,很多功能也比较高级,当项目中有需求的时候再去看文档学习!

辅助工具

微信端打开

function is_weixin(){  
    var ua = navigator.userAgent.toLowerCase();  
    if(ua.match(/MicroMessenger/i)=="micromessenger") {  
        return true;  
    } else {  
        return false;  
    }  
}

微信标题

.factory('Title', function () {
      // 原生触发
      return {
          changeTitle: function (title) {
              var body = document.getElementsByTagName('body')[0];
              document.title = title;
              var iframe = document.createElement("iframe");
              iframe.setAttribute("src", "/img/favicon.ico");
              function listener() {
                  setTimeout(function () {
                      iframe.removeEventListener('load', listener);
                      document.body.removeChild(iframe);
                  }, 0);
              }
              iframe.addEventListener('load', listener);
              document.body.appendChild(iframe);
          }
      }
})

浏览器缓存

由于微信会缓存静态文件,导致代码更新时不能及时反应过来,通过给文件添加版本号或者时间戳的方式来消除影响。

<script src=”a.js?v=123”></script>
<script src=”a.js?t=123”></script>


留言