1年前小程序很火,从跳一跳到现在越来越多的企业都开发了小程序版本,我所在的公司也不例外,当时参与的项目也需要开发小程序,而我们公司还没有这方面需求所以几乎没有人会。
我只有硬着头皮边自学边开发,两个月后上线了第一版,开心到飞起。
下面是当时遇到坑后自己总结的,由于以下是一年前写的,不知道现在的小程序版本更新成什么样了,可能有些问题已经换了实现。仅供参考。
1、每次请求会改变sessionId
调用 wx.request() 时,每次都会改变sessionId导致登录状态失效。
解决办法:登录后获取返回的sessionId,存到一个固定的地方,比如app.js的globalData里,然后在调用请求时在header里加上该session的cookie。
wx.request({
url: 'login.php', // 登录接口,仅为示例,并非真实的接口地址
data: {
x: '' ,
y: ''
},
header: {
'content-type': 'application/json', // 默认值
'Cookie': getApp().globalData.cookie // globalData定义一个cookie变量,存sessionId
},
success: function(res,header) {
let cookie = header['Cookie'] // 获取后台返回的sessionId
// cookie = ... // 其他操作
getApp().globalData.cookie = cookie // 赋值到全局变量
}
})2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2、登录获取 unionId 遇到的坑
获取unionId的途径:
绑定了开发者帐号的小程序,可以通过下面3种途径获取UnionID。
调用接口wx.getUserInfo,从解密数据中获取UnionID。注意本接口需要用户授权,请开发者妥善处理用户拒绝授权后的情况。
如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号。开发者可以直接通过wx.login获取到该用户UnionID,无须用户再次授权。
如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用。开发者也可以直接通过wx.login获取到该用户UnionID,无须用户再次授权。
原文地址:https://developers.weixin.qq.com/miniprogram/dev/api/uinionID.html
也就是说获取步骤是:
根据 wx.login() 获取code -> 根据 code 和官方接口获取 unionId
但是,有时候根据接口返回的 unionId 是 null,这时候就遇到了第一个坑
// ============ 我不是分割线 ==============
坑一:unionId返回为空,需要从微信个人信息数据中获取加密数据然后解密得到unionId 解决办法:
1、获取 session_key
根据官方接口
返回数据中获取 String session_key = json.getString("session_key")
2、获取 encryptedData 和 iv
wx.getUserInfo({
success: res => {
console.log(res) // res中含有需要解密unionId的数据"encryptedData"和"iv"
}
})2
3
4
5
3、session_key、encryptedData、iv 传到后台接口,解密获取unionId,解密代码:
AES.java
package com.xxxxx.sfal.web.common.decrypt;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
/**
* CreationTime: 2018/3/29 17:46.
*/
public class AES {
public static boolean initialized = false;
/**
* AES解密
*
* @param content 密文
* @return
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
initialize();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
byte[] result = cipher.doFinal(content);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void initialize() {
if (initialized) return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
//生成iv
public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
Cotroller,返回解密后的unionId
@RequestMapping(value = "/decryptUnionId", method = RequestMethod.POST)
public ApiResponse<?> decryptUnionId(JSONObject json) {
try {
AES aes = new AES();
byte[] resultByte = aes.decrypt(Base64.decodeBase64(json.getString("encryptedData")), Base64.decodeBase64(json.getString("session_key")), Base64.decodeBase64(json.getString("iv")));
if (null != resultByte && resultByte.length > 0) {
String userInfo = new String(WxPKCS7Encoder.decode(resultByte), "UTF-8");
JSONObject jsonObject = JSON.parseObject(userInfo);
return ApiResponse.itemSuccess(jsonObject.getString("unionId"));
}
} catch (InvalidAlgorithmParameterException e) {
logger.error("无效的算法参数异常", e);
} catch (Exception e) {
logger.error("解密出错", e);
}
return null;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
用到的包:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk16</artifactId>
<version>1.46</version>
</dependency>2
3
4
5
// ========= 我不是分割线 ==========
坑二:解密encryptedData时报错:pad block corrupted
我猜原因可能是code与session_key不符导致的,有可能会不小心请求了两次code,而session_key是根据code得到的,可能解密时候用的是第二次请求的code,而session_key对应的是第一次的code,导致解密失败;
解决办法:
一定要按照这个顺序:先通过wx.login()获取到code,然后再根据wx.getUserInfo()获取到encryptedData、iv,三个参数传到后台,后台先根据code获取unionId,判断unionId是否为空,如果不为空直接返回,如果为空,就根据encryptedData、iv、session_key解密得到unionId。
@RequestMapping(value = "/getUnionIdForMiniApp", method = RequestMethod.POST)
public ApiResponse<?> getUnionIdForMiniApp(@RequestBody JSONObject json) {
RestTemplate template = new RestTemplate();
String tokenUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={APPID}&secret={SECRET}&js_code={JSCODE}&grant_type=authorization_code";
String result = template.getForObject(tokenUrl, String.class, mina_appid, mina_secret, json.getString("jscode"));
JSONObject jsonBack = JSON.parseObject(result);
String session_key = jsonBack.getString("session_key");
String unionId = jsonBack.getString("unionid");
if (StringUtils.isBlank(unionId)) {
unionId = decryptUnionId(session_key, json);
}
return ApiResponse.itemSuccess(unionId);
}
private String decryptUnionId(String session_key, JSONObject json) {
// 根据encryptedData、iv、session_key解密得到unionId
return null;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
以上代码仅供参考,unionId为重要数据,一般来说不要返回到客户端,可以用自己的一套加密方式加密再返回
3、下拉刷新遇到的坑
实现下拉刷新,先在对应的json配置文件里加上 "enablePullDownRefresh": true
然后在对应的函数里写代码
Page({
onPullDownRefresh: function(){
console.log('下拉了...')
}
})2
3
4
5
坑一:下拉刷新的三个点不见了
解决:json配置文件加上:"backgroundTextStyle": "#000"
(颜色随便改)
坑二:下拉后不弹回去
解决:
Page({
onPullDownRefresh: function(){
console.log('下拉了...')
wx.stopPullDownRefresh() // 执行完自定义操作后关闭下拉刷新
}
})2
3
4
5
6
4、Web-view chrome调试 解决方案
微信小程序连接谷歌浏览器调试
- 用微信打开http://debugx5.qq.com 这个地址
- 下载TBS内核
- 在信息中打开TBS内核Inspector调试
- 连接手机可以调试小程序web-view页面