• OkHttp全局拦截器设置token超时重新获取


    Feign客户端请求远程服务接口时,需要携带token进行认证(详见《微服务迁移记(六):集成jwt保护微服务接口安全》),token有超时时间设置,当超时后,需要重新刷新token。如果每个接口都去判断,那就费事了,最好的办法是在拦截器里做。我这里使用的是OkHttp,新增一个OkHttpInterceptor的拦截器:

    @Slf4j
    public class OkHttpInterceptor implements HandlerInterceptor,Interceptor {
            @Autowired
        private ApiInitService apiInitService;
        @Autowired
        private RedisUtil redisUtil;
        @Value("${app_id}")
        String app_id;
        @Value("${app_secret}")
        String app_secret;
    
        @Override
        public Response intercept(Chain chain) throws IOException {
            log.info("进入okhttp拦截器");
            Request request = chain.request();
            try {
                Response response = chain.proceed(request);
                ResponseBody responseBody = response.body();
                BufferedSource source = responseBody.source();
                source.request(Long.MAX_VALUE);
                Buffer buffer = source.getBuffer();
                MediaType mediaType = responseBody.contentType();
                if(isPlaintext(buffer)){
                    Charset charset = Charset.forName("UTF-8");
                    String result = buffer.clone().readString(mediaType.charset(charset));
                    log.info("result:"+result);
                    //如果token超时或不存在,则重新获取
                    ResponseData responseData = JSONObject.parseObject(result,ResponseData.class);
                    if(responseData.getCode() == CodeEnum.UNKNOWNTOKEN.getCode()){
                        //重新获取token
                        String tokenData = this.apiInitService.getToken(app_id,app_secret);
                        if(StringUtils.isNotEmpty(tokenData)){
                            //重新将token存到redis中
                            redisUtil.set("Authorization",tokenData);
                        }
                    }
                }
                return response;
            }catch (Exception e){
                throw  e;
            }
        }
    
        /**
         * Returns true if the body in question probably contains human readable text. Uses a small sample
         * of code points to detect unicode control characters commonly used in binary file signatures.
         */
        static boolean isPlaintext(Buffer buffer) throws EOFException {
            try {
                Buffer prefix = new Buffer();
                long byteCount = buffer.size() < 64 ? buffer.size() : 64;
                buffer.copyTo(prefix, 0, byteCount);
                for (int i = 0; i < 16; i++) {
                    if (prefix.exhausted()) {
                        break;
                    }
                    int codePoint = prefix.readUtf8CodePoint();
                    if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
                        return false;
                    }
                }
                return true;
            } catch (EOFException e) {
                return false; // Truncated UTF-8 sequence.
            }
        }
    
        private boolean bodyEncoded(Headers headers) {
            String contentEncoding = headers.get("Content-Encoding");
            return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity");
        }
    }

    注意,这里不需要加@Components,因为我在这个控制器里有注入Service和RedisUtil以及配置项,如果直接扫包方式载入,会造成注入对象为null的错误。具体原因是拦截器是在Springcontext之前加载。

    新增一个Okhttp的配置类:

    @Configuration
    @ConditionalOnClass(Feign.class)
    @AutoConfigureBefore(FeignAutoConfiguration.class)
    @Slf4j
    public class OkHttpClientConfig {
    
        private OkHttpClient okHttpClient;
    
        @Bean
        public OkHttpInterceptor okHttpInterceptor(){
            return new OkHttpInterceptor();
        }
    
        
        @Bean
        public okhttp3.OkHttpClient okHttpClient(OkHttpClientFactory okHttpClientFactory,
                                                 FeignHttpClientProperties httpClientProperties) {
            this.okHttpClient = okHttpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).connectTimeout(httpClientProperties.getConnectionTimeout(),TimeUnit.SECONDS)
                    .followRedirects(httpClientProperties.isFollowRedirects())
                    .addInterceptor(okHttpInterceptor())
                    .build();
            return this.okHttpClient;
        }
    }

    配置这个类时,我一开始犯了一个错误,抄了网上一段代码,直接在增加拦截器时使用了:

    .addInterceptor(new OkHttpInterceptor())

    这种方式和为拦截器加注解一样,并不能提前加载拦截器,所以需要如上面的代码,将拦截器独立出来一个bean,将这个bean加入到okhttp即可。

  • 相关阅读:
    【像程序员一样思考】读书笔记4
    MFC ListControl 与 Excel 数据的导入导出
    OpenCV中findContours函数的使用
    十大算法
    qsort对二维数组的排序
    【像程序员一样思考】读书笔记3
    【像程序员一样思考】 读书笔记2
    【像程序员一样思考】 读书笔记1
    代码混淆
    布局优化
  • 原文地址:https://www.cnblogs.com/zhouyu629/p/13276370.html
Copyright © 2020-2023  润新知