【JAVA】自定义异常全局处理 企业微信(微信)token 过期问题


3/7/2020 java

背景:企业微信第三方应用开发,存在三种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

思路如下:自定义异常,捕获微信或企业微信 特定异常码,全局异常处理器 处理对应异常,实现自动刷新 例如:企业微信 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

在请求企业微信时,需要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

微信token 自动刷新处理思路也是如此,关键点在于:

  1. 找到请求微信(企业微信)api,需要token(获取ticket,etc)的地方,分析可能会出现什么问题
  2. 制造条件复现出该问题,找到对应的 错误码,进行处理

popo先生的博客