开发微信公众号真是一堆坑, 自己踩过了, 开发前耐着性子看一遍.
授权回调必须在微信浏览器里, 不同Ajax调用会跨域…
接口调试都是在线的, 还好有NATAPP这玩意…
MP_verify_xxxxxxxx.txt只在你设置域名时才校验…
[TOC]
1 公众号开发准备
1.0 微信公众平台与开放平台
(1) 公众平台: https://mp.weixin.qq.com/ 微信客户端里的公众号开发相关;
(2) 开放平台: https://open.weixin.qq.com/ App相关接入微信;
(3) 商户平台: https://pay.weixin.qq.com/ 你把钱支付给谁;
(4) 区别: 开发App支付,分享, 登录就去开放平台. 开发公众号网页里的分享,支付就去公众平台.
1.1 申请公众号(服务号)
(1) 类型: 订阅号, 服务号, 企业号, 小程序
(2) 区别: 服务号可以使用公众号支付, 个人不能申请服务号;
(3) 服务认证每年要认证, 认证费300元/年.
(4) 服务号认证后可不受限制调用接口; 没有认证无法使用公众号分享等接口;
(5) 服务号及个人的订阅号都可以使用开发者工具里的”公众平台测试帐号”去测试相关接口, 测试时需要把相关测试人员加到测试组;
(6) 可以使用开发者工具里的”在线接口调试工具”去验证接口相关参数
2 公众平台
2.1 公众号分享
2.1.1 登录公众号, 设置业务域名
业务域名每月只能修改3次, 且要在相关目录下放验证MP_verify_xxxxxxxx.txt文件. 这个可能是微验证域名是否真实有效才加的, ICP备案域名设置完后就不在input框弹出”防欺诈盗号…”提醒.
2.1.2 设置JS安全域
设置了JS安全域名后就可以在这个域调用jsapi接口
2.1.3 设置授权回调域
这个域名在微信OAuth2.0获了用户授权时会回校验这个域名; 同样需要校验MP_verify_xxxxxxxx.txt
公众分享暂时用不到这个接口.
2.1.4 公众号AppId和AppSecret在那里
这两个参数在公众号开发过程中比较重要, 一直会用到. 注意开放平台也有AppId;不要搞混了;
2.1.5 开发文档
开发者工具 -> 开发者文档 -> https://mp.weixin.qq.com/wiki ->
微信网页开发-> 微信JS-SDK说明文档: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
另一个神一样链接: http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
内容差不多, 我参考是下面这个;
2.1.6 引入JS文件
http://res.wx.qq.com/open/js/jweixin-1.0.0.js
支持https
2.1.7 通过config接口注入权限验证配置, 并设置分享菜单功能;
完整微信分享代码:
1 | wx.config({ |
看到这个里大家可能要问这些参数是从那里来的? 看下面, 文档组织太烂了
先要获取access_token再获取jspai_ticket,再经过签名算法生成config所需要的几个参数;
2.1.8 先获取access_token
access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。
参考:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183&token=&lang=zh_CN
Requset:
1 | GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET |
Response:
1 | {"access_token":"ACCESS_TOKEN","expires_in":7200} |
APPID和APPSECRET 开发-> 基本配置里获取.
ACCESS_TOKEN时效7200秒
为这安全这步最好在后台实现
2.1.9 再获取jsapi_ticket
Request:
1 | https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi |
Response:
1 | { |
2.1.10 签名算法
参考: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
(1). 签名生成规则如下:
参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
(2) 示例:
1 | noncestr=Wm3WZYTPz0wzccnW |
对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1:
1 | jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value |
对string1进行sha1签名,得到signature:
1 | 0f9de62fce790f9a083d5c99e95740ceb90c27ed |
看到这里wx.config里需要参数就都有了
timestamp: , // 必填,生成签名的时间戳
nonceStr: ‘’, // 必填,生成签名的随机串
signature: ‘’,// 必填,签名,见附录1
2.1.11 代码调试
(1) 下载微信开发者工具
https://mp.weixin.qq.com/wiki?action=doc&id=mp1455784140&t=0.2745196293017851&token=&lang=zh_CN#6
(2) 开发者工具使用
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455784140&token=&lang=zh_CN
(3) 注册项: android按提示一步步进行没有多大问题. ios除了要在同一网段,还要注意手机上代理的配置, 见下图手机
2.2 公众号支付
2.2.1 支付目录设置
注这里是公众号支付在微信浏览器里面运行, 如果是微信App支付请到公众平台里操作; 公从平台提供jar里来调用微信支付; 微信App支付是跨Apk的, 公众里支付就是在微信里操作的;
(1) 登录公众号设置网页授权域名
(2) 设置支付目录
如果是测试可以设置支付测试目录, 添测试白名单的人才要可以使用支付;
2.2.2 公众号里拉调微信支付
参考:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN
跟上面分享一样, 先引用http://res.wx.qq.com/open/js/jweixin-1.0.0.js, 再设置wx.config,注意jsApiList参数中加上chooseWXPay接口
1 | wx.config({ |
看到这里, 问题又来了, 这些参数从那里来? 且看下面.
2.2.3 公众号支付整体流程
参考商户平台文档: https://pay.weixin.qq.com/wiki/doc/api/img/chapter7_4_1.png
简单描述:
- A. 后台获调用统一下单接口完成下单生成(prepay_id), 注意: App支付和公众号支付(JSAPI)的统一下单接口一样, 参数不一样, 公众号支付(JSAPI)需要多传一个用户的openId;
- B. 用户点击公众号页面的支付按钮 -> JSAPI(wx.chooseWXPay({prepay_id …})) -> 打开微信支付 -> 完成支付
- C. 跳转公众号页面
2.3.4 统一下单(商户平台):
(1). URL地址:POST https://api.mch.weixin.qq.com/pay/unifiedorder
注: 商户平台的接口都是https + POST + XML方式, 且有些接口需要证书
又是不很绕的地方, 两个统一下单文档:
公众号支付: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
App支付: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
两个里参数有些不一样: appId, openId(App支付不需要, 公众号支付需要openId, 下面[获取用户授权](#2.3.5 获取用户授权)会介绍获取OpenId).
(2) 签名算法:
https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
(3) 签名验证工具:
https://pay.weixin.qq.com/wiki/tools/signverify/
(4) 统一下单完成就得到wx.chooseWXPay所需要参数了;
商户平台没有登录过, 这里不做过多介绍.
2.3.5 获取用户授权后得到openId
参考: 网页授权获取用户基本信息 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842&token=&lang=zh_CN
另一个文档: https://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
2.3.5.1 注意事项
(1) 登录公众号设置网页授权域名
(2) 授权有静默授权和非静默授权
静默授权, 用户无感知 只能获取openId; 非静默会弹出授权页面(如下:), 可以获取用户昵称,头像等(详见:https://mp.weixin.qq.com/wiki/14/bb5031008f1494a59c6f71fa0f319c66.html).
(3) 获取授权流程: JS调用同步接口回调用得到授权码 -> 用授权码获取OpenId和access_token -> 再获取用户其它信息;
(4) openId是一个微信号对一个公众号是唯一, 一个微信不同公众号是不同的.
openId = 加密(微信号, 公众号)
(5) openId不会变, 每次获取是一样的;
(6) 获取授权接口比较繁, 具体可以了解OAuth2.0, 另一篇阮一峰: 理解OAuth 2.0
2.3.5.2 用户授权,回调获取授权码code
(1) 必须在微信浏览器执行;
(2) 不能后台发送HTTP请求, 会返回必须在浏览执行提示;
(3) 不能Ajax方式因为会跨域;
(4) 不能iframe方式, 微信浏览器不会招待;
(5) 只使用url跳转方式, 猜想这个接口直接就右微信浏览器里redirect了;
(6) APPID - 公众号里基本配置里
(7) REDIRECT_URI - 回调的url可以带参数http://xxx.xzv/sdf?a=b&c=d, 必须encodeURIComponent编码否则回调时参数就丢失了;
(8) STATE 随你传吧, 感觉REDIRECT_URI带参数就可以了. STATE会保证回调给你;
(9) 示例
1 | // 请求 |
(10) 回调会在你传的REDIRECT_URI参数后再添加code和state参数
(11) 通过code换取网页授权access_token和openId
2.3.5.3 通过code换取网页授权access_token和openId
(1) APPID - 公众号里基本配置里AppId;
(2) SECRET - 公众号里基本配置里AppSecret;
(3) CODE - 上一步获取的;
(4) 考虑安全这一步必须在后台进行;
(5) 接口返回:
1 | { |
(6) 这里已经获取openId, 就可以进统一下单了; 下单完成获取prepay_id -> wx.chooseWXPay -> 进入微信支付流程;
(7) access_token是有时效的, 可以能过这里获取REFRESH_TOKEN调用刷新refresh_token接口重新获取
(8) 获用access_token可以进一步获取用户详细信息
3 本地开发
3.1 使用NATAPP(ngork)进行微信本地开发调试
NATAPP基于ngrok的国内高速内网穿透服务,
https://natapp.cn/
(1) 下载natapp
(2) 运行, 参考: https://natapp.cn/article/natapp_newbie
(3) 默认是绑定在80端口, 免费版不可修改, 收费版本可修改;
(4) 免费版本使用nginx转发端口
(5) 用Natapp(ngrok)进行微信本地开发调试 https://natapp.cn/article/wechat_local_debug
3.2 Nginx端口转发
- 安装Nginx
1 | brew search nginx |
/usr/local/var/ww
/usr/local/etc/nginx/nginx.conf
nginx will load all files in /usr/local/etc/nginx/servers/.
- 代理, 把80端口请求转到proxy_pass指定地址;
1 | isten 80; |
- 启动/停止
1 | brew services start nginx // 随系统自启动; |
3.3 Spring中处理MP_verify_XXXX.txt问题
1 |
|
3.4 微信android手上链接不跳转
如果链接上有你自己wifi的Ip地址就不会跳转, 很奇葩的
1 | window.location.href='http://www.baidu.com?t=你手机wifi的ip地址' |