写在前面
- 微信js-sdk的使用和调试需要外网可访问的服务,因为微信要发起请求到你的服务验证,所以请预先准备好。
- 关于本地调试可以借助natapp内网穿透工具,相关操作请访问官网https://natapp.cn/,可注册领取两条免费隧道,官网使用帮助文档也很齐全。这样你启动本地服务,也能进行微信的相关功能测试。
一、后端(服务端)准备
后端主要准备两个接口:一个接收微信发起的token验证;一个接收前端的请求返回微信权限验证配置;
以下直接贴代码,有些方法和类就不贴出来了,一目了然也好理解自己搞定一下
package com.example.wxserver.controller;
import com.example.wxserver.domain.vo.WxAccessTokenVo;
import com.example.wxserver.domain.vo.WxAuthVo;
import com.example.wxserver.domain.vo.WxTicketVo;
import com.example.wxserver.utils.NonceGenerator;
import com.example.wxserver.utils.SHA1Encryption;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.Date;@RestController
@RequestMapping("/wx")
public class WxController {static final String appid = "测试号申请页的appID";static final String secret = "测试号申请页的appsecret";// access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。// access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。// 避免频繁调用微信token,此处作为调试临时缓存一下static WxAuthVo wxAuthVoSession = null;/*** 接收微信发起的token验证* 在微信测试号申请时,接口配置一栏填写后会发起请求到此接口,并默认携带相关参数* 将token(测试号申请页面,接口配置填写的Token)、timestamp、nonce三个参数进行字典序排序* 排序后三个参数字符串拼接成一个字符串进行sha1加密* 获得加密后的字符串可与signature对比,一致的话就原样返回echostr,此后接口配置显示成功* @param signature 微信加密签名* @param timestamp 时间戳* @param nonce 随机数* @param echostr 随机字符串* @return echostr*/@GetMapping("/checkSignature")public String checkSignature(String signature, String timestamp, String nonce, String echostr) {final String token = "mytoken";String[] arr = {token, timestamp, nonce};Arrays.sort(arr);String sign = SHA1Encryption.encryption(String.join("", arr));if (sign.equals(signature)) {return echostr;}return "";}/*** 接收前端请求* 发起请求到微信服务,并返回权限验证信息给前端页面* 先获取微信accessToken,c通过accessToken获取微信jsapi_ticket* 生成signature签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同* 所以最终要将生成签名用的这两个字段返回给前端的* @param url 调用JS接口页面的完整URL* @return wx.config用到的相关信息*/@GetMapping("/get-auth")public WxAuthVo getWxAuth(String url) {if (wxAuthVoSession != null) return wxAuthVoSession;WxAuthVo wxAuthVo = new WxAuthVo();RestTemplate restTemplate = new RestTemplate();// 获取微信accessTokenfinal String wxTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;WxAccessTokenVo accessTokenVo = restTemplate.getForObject(wxTokenUrl, WxAccessTokenVo.class);System.out.println("获取accessToken:" + accessTokenVo);if (accessTokenVo != null && accessTokenVo.getAccess_token() != null) {// 获取微信jsapi_ticketfinal String wxTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessTokenVo.getAccess_token() + "&type=jsapi";WxTicketVo wxTicketVo = restTemplate.getForObject(wxTicketUrl, WxTicketVo.class);System.out.println("获取wxTicket:" + wxTicketVo);if (wxTicketVo != null && "ok".equals(wxTicketVo.getErrmsg())) {String noncestr = NonceGenerator.generatorNonce();long timestamp = new Date().getTime();String signature = SHA1Encryption.encryption("jsapi_ticket=" + wxTicketVo.getTicket() + "&noncestr=" + noncestr + "×tamp=" + timestamp + "&url=" + url);wxAuthVo.setSignature(signature);wxAuthVo.setTimestamp(timestamp);wxAuthVo.setNonceStr(noncestr);wxAuthVo.setAppId(appid);wxAuthVoSession = wxAuthVo;}}return wxAuthVo;}
}
二、微信测试号配置
微信公众账号测试号申请系统传送门
打开以上链接,登录后可见以下页面,这就是上一步提到的微信测试号配置页面:
页面往下还有具体的接口权限介绍,注意网页网页授权获取用户基本信息还需单独配置
三、前端使用
- 首先用到的微信sdk版本,注意不同版本的差异,会影响相关方法的使用
<script src="http://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
- 微信方法测试准备页面
特别说明一下:针对于微信的分享朋友,朋友圈功能,也就是updateAppMessageShareData,updateTimelineShareData两个方法,只是配置分享的内容,至于发起分享这个动作,还得通过微信右上角的三个点弹出的菜单进行操作。并非页面内自定义一个按钮,点击发起分享。且这两个方法必须在测试公众号下访问才能成功,测试的chooseImage方法则没有这个要求。至于别的方法与sdk版本,还请自行测试。
<body><button id="chooseImage">选照片</button>
</body>
<script>function initWxConfig() {// 创建一个新的 XMLHttpRequest 实例const xhr = new XMLHttpRequest();// 请求后端准备的接口,并把url传过去xhr.open('GET', '/wx/get-auth?url=' + window.location.href);// 设置请求完成的回调函数xhr.onreadystatechange = function () {// 请求完成并且响应状态码为 200if (xhr.readyState === XMLHttpRequest.DONE) {if (xhr.status >= 200 && xhr.status < 300) {// 处理请求响应的数据const response = JSON.parse(xhr.responseText);const {appId, nonceStr, signature, timestamp} = response;console.log('response', response);wx.config({debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。appId, // 必填,公众号的唯一标识timestamp, // 必填,生成签名的时间戳nonceStr, // 必填,生成签名的随机串signature,// 必填,签名jsApiList: ['updateAppMessageShareData','chooseImage','updateTimelineShareData'] // 必填,需要使用的JS接口列表});wx.ready(function () {// config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。console.log("微信初始化成功~")wx.updateAppMessageShareData({title: '测试分享给朋友', // 分享标题desc: '这是一条描述信息用来测试的', // 分享描述link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: 'https://img-blog.csdnimg.cn/direct/fe0aba524001438b99ec91063d5c00dd.png#pic_center', // 分享图标success: function () {// 设置成功console.log('分享朋友设置成功')}})wx.updateTimelineShareData({title: '测试分享到朋友圈', // 分享标题link: window.location.href, // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致imgUrl: 'https://img-blog.csdnimg.cn/direct/fe0aba524001438b99ec91063d5c00dd.png#pic_center', // 分享图标success: function () {// 设置成功console.log('分享朋友圈设置成功')}})});wx.error(function (res) {// config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。console.log("微信初始化失败:", res)});} else {// 处理错误,例如 404 或 500 状态码console.error('Error: ' + xhr.status);}}};xhr.send();}initWxConfig()chooseImage.onclick = function (){console.log("选取照片")wx.chooseImage({count: 1, // 默认9sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有success: function (res) {var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片console.log('localIds', localIds)}});}
</script>
四、测试截图
这里的测试链接,必须符合微信测试号配置的安全域名,以下就是成功了
参考文档:
1.微信网页开发 /JS-SDK说明文档
2.关于接口配置信息URL和Token说明
3.获取 Access token原文介绍
4.获取 jsapi_ticket原文介绍