背景:企业微信第三方应用开发,存在三种token, cropToken(企业级别token),suitToken(应用级别token),providerToken(服务商级别token); 对于一个服务商而言,问题一:测试环境和生产环境 的 providerToken 会存在竞争关系,问题二:多次请求 providerToken,token未过期时,获取到的数据一样, 数据结构如ProviderToken 数据结构, 过期时间一直为 7200s,(ΩДΩ) 但不知道token 何时生效的,所以有效时间0<x<7200s,不知何时过期,所以需要在token 过期时,自动刷新token
ProviderToken 数据结构:
{
"provider_access_token":"XXXXXXXXXXXXXXXX",
"expires_in":7200
}
1
2
3
4
2
3
4
思路如下:自定义异常,捕获微信或企业微信 特定异常码,全局异常处理器 处理对应异常,实现自动刷新 例如:企业微信 token 无效 状态码为 40014,invalid access_token
处理逻辑如下: 自定义企业微信请求异常
package ky.edu.saas.exception;
import lombok.Data;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
/**
* 企业微信api调用的异常封装
* errcode 参见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433747234&token=&lang=zh_CN
*/
@Data
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class QYWXAPIAccessException extends RuntimeException {
/**
* 错误码
*/
private String errcode;
/**
* 错误信息
*/
private String errmsg;
/**
* 对应类型,例:crop:ww031b410ce418c708;suit;provider, 其中 crop 包含 需要刷新的 corpId
*/
private String typeString;
/**
* 通过errcode和errmsg构造
*
* @param errcode 微信返回的errcode
* @param errmsg 微信返回errmsg
* @param typeString 对应类型,例:crop:ww031b410ce418c708;suit;provider, 其中 crop 包含 需要刷新的 corpId
* suiteTicket;
*/
public QYWXAPIAccessException(String errcode, String errmsg, String typeString) {
super(String.format("errcode:%s, errmsg:%s", errcode, errmsg));
this.errcode = errcode;
this.errmsg = errmsg;
this.typeString = typeString;
}
}
1
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
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
在请求企业微信时,需要token(无论哪种token)并且请求失败后,抛出此异常; 然后定义自定义异常处理器,捕获并处理该异常,然后抛出异常
package ky.edu.saas.handler;
import ky.edu.saas.datasync.domain.service.CropService;
import ky.edu.saas.datasync.domain.service.ProviderService;
import ky.edu.saas.datasync.domain.service.SuiteService;
import ky.edu.saas.exception.QYWXAPIAccessException;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.Map;
/**
* 微信api调用的异常封装
* errcode参见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433747234&token=&lang=zh_CN
*/
@RestControllerAdvice
@RequiredArgsConstructor
public class CustomizeExceptionHandler extends RuntimeException {
private final ProviderService providerService;
private final CropService cropService;
private final SuiteService suiteService;
/**
* 捕获CustomException
*
* @param e
* @return json格式类型
*/
@ResponseBody
@ExceptionHandler({QYWXAPIAccessException.class}) //指定拦截异常的类型
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) //自定义浏览器返回状态码
public ModelAndView customExceptionHandler(QYWXAPIAccessException e) {
Map<String, Object> map = new HashMap<>();
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("error");
modelAndView.addObject(map);
String typeString = e.getTypeString();
if (e.getErrcode().equals("40014") && StringUtils.isNotBlank(typeString)) {
if (typeString.contains("crop:")) {
cropService.getCropToken(typeString.split(":")[1], true);
} else if (typeString.equals("suit")) {
suiteService.getSuiteToken(true);
} else if (typeString.equals("provider")) {
providerService.getProviderToken(true);
}
}
return modelAndView;
}
}
1
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
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
微信token 自动刷新处理思路也是如此,关键点在于:
- 找到请求微信(企业微信)api,需要token(获取ticket,etc)的地方,分析可能会出现什么问题
- 制造条件复现出该问题,找到对应的 错误码,进行处理