这章主要记录下调用微信JS-SDK中的扫一扫踩到的坑
一、引入JS文件
- 首先我们先引入js文件,地址为 http://res.wx.qq.com/open/js/jweixin-1.0.0.js,当然你也可以下载到本地,使用本地路径进行引入
- 如果是前后端分离的项目,可以用npm来安装相关依赖,具体命令为 npm install weixin-js-sdk,然后在相应页面引入即可,具体命令为 import wx from ‘weixin-js-sdk’
二、往服务端传入当前页面url
- 这里需要往服务端传入当前页面的url,包括’http(s)://’部分,以及’?’后面的GET参数部分,但不包括’#’hash后面的部分,此外该url需要经过 encodeURIComponent 处理,由于我只在一个页面调用了扫一扫的功能,所以我的页面url直接写死了,但如果你需要调用分享等功能,则页面的url需要通过 location.href.split(‘#’)[0] 动态获取,具体的见官方文档
- 我的页面url参数为 var url = encodeURIComponent(‘https://www.baidu.com/‘),注意,这里我碰到一个很坑的事,后期在页面上调用扫一扫时,该url和扫一扫所在页面的url必须保持一致,我都填对了,可还是报错,最后才查出来,扫一扫所在的页面url末尾多了一个/,所以在往服务端传的url后面也加上一个/,就没问题了
三、在微信公众平台设置JS接口安全域名
- 该域名必须与第二步中url的域名相同
- 还需要下载 MP_verify_xyPkykStkhZUf7ya.txt 文件,并将其上传至项目的根目录下,也就是说通过 域名 + /MP_verify_xyPkykStkhZUf7ya.txt 的形式能直接访问到该文件
四、获取jsapi_ticket
用于调用微信JS接口的临时票据,有效期为7200s,由于调用次数十分有限,所有我们需要全局缓存jsapi_ticket,可以通过 redis 来缓存,在获取 jsapi_ticket 时需要先获取 access_token,不清楚怎么获取的小伙伴可以点击看我以前的博客
public static String getWXJsapiTicket(String accessToken) {
// 此处accessToken为请求微信接口获取到的access_token
String jsapiTicketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?" +
"access_token=" + accessToken +
"&type=jsapi";
JSONObject jsonObject = HttpUtils.httpsRequest(jsapiTicketUrl, "GET", null);
return (String) jsonObject.get("ticket");
}
五、服务端生成签名
- 生成签名需要四个参数,分别为 noncestr,jsapi_ticket,timestamp,url
- noncestr
随机字符串 - jsapi_ticket
用于调用微信JS接口的临时票据,即第三步获取到的jsapi_ticket - timestamp
当前时间戳,单位为秒 - url
当前页面url,即第二步由页面传递给服务端的url参数
- noncestr
WXPayUtils
public static String generateNonceStr() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
public static long getCurrentTimestamp() {
return System.currentTimeMillis()/1000;
}
- 用SHA1加密生成签名
@RequestMapping("xxxxxxxxxxxxx")
@ResponseBody
public Map<String, Object> getSignature(HttpServletRequest request) {
String nonceStr = WXPayUtils.generateNonceStr();
String timestamp = WXPayUtils.getCurrentTimestamp() + "";
// returnMap为返回给页面的数据
Map<String, Object> returnMap = new HashMap<>();
// 此处填写你自己公众号的appid
map.put("appId", WXConstants.APPID);
map.put("timestamp", timestamp);
map.put("nonceStr", nonceStr);
// map为用于生成签名的数据
Map<String, Object> map = new HashMap<>();
map.put("timestamp", timestamp);
map.put("noncestr", nonceStr);
map.put("jsapi_ticket", jsapiTicket);
map.put("url", request.getParameter("url"));
String signature = SHA1.getJsSHA1(map);
if (null != signature) {
returnMap.put("signature", signature);
}
return returnMap;
}
SHA1
/**
* 用SHA1算法生成安全签名
* @param map
* @return 安全签名
* @throws AesException
*/
public static String getJsSHA1(Map<String, Object> map) {
try {
String[] array = new String[] { "noncestr", "jsapi_ticket", "timestamp", "url" };
Arrays.sort(array);
StringBuffer sb = new StringBuffer();
// 字符串排序
for (int i = 0; i < array.length; i++) {
if (i < array.length-1) {
sb.append(array[i]).append("=").append(map.get(array[i])).append("&");
} else {
sb.append(array[i]).append("=").append(map.get(array[i]));
}
}
String str = sb.toString();
// SHA1签名生成
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(str.getBytes());
byte[] digest = md.digest();
StringBuffer hexstr = new StringBuffer();
String shaHex = "";
for (int i = 0; i < digest.length; i++) {
shaHex = Integer.toHexString(digest[i] & 0xFF);
if (shaHex.length() < 2) {
hexstr.append(0);
}
hexstr.append(shaHex);
}
return hexstr.toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
六、通过config接口注入权限验证配置
- 先执行wx.config方法,注入权限验证配置
// 页面一加载时执行该方法
getWXJsapiTicket() {
// 此处需要将url用ajax传递给服务器,并接收返回来的参数
// .........
wx.config({
// 开启调试模式,调用的所有api的返回值会在客户端alert出来
// 若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印
debug: false,
// 此处填写服务端返回的appId
appId: appId,
// 此处填写服务端返回的时间戳
timestamp: timestamp,
// 此处填写服务端返回的随机字符串
nonceStr: nonceStr,
// 此处填写服务端返回的签名
signature: signature,
// 需要使用的JS接口列表,我只用到了扫一扫,所以只填写了scanQRCode
// 如果需要其他JS接口,可以参考官方文档
jsApiList: ['scanQRCode']
});
}
- 执行完wx.config方法后,执行某一点击事件,然后执行wx.scanQRCode方法,调用微信扫一扫
// 此为一点击事件
scanCode() {
wx.scanQRCode({
// 默认为0,扫描结果由微信处理,1则直接返回扫描结果
needResult: 0,
// 可以指定扫二维码还是一维码,默认二者都有
scanType: ["qrCode","barCode"],
success: function (res) {
// 当needResult 为 1 时,扫码返回的结果
let result = res.resultStr;
}
});
}
不出意外的话,就可以在页面里正常地调用微信扫一扫了