如何拦截feign访问的返回结果

程序员周瑜 2020-07-05 09:29:50
springcloud微服务,使用feign做rpc。
远程服务使用jwt做接口保护,每次访问时,添加一个header,通过拦截器实现RequestInterceptor接口,往每次请求url中塞一个header。
但这个token有保存期限,当服务端过期后,客户端会接收到一个错误,token超时。

如何像请求一样,在每个feign客户端的返回结果中判断,如果超时,就重新获取一次token?类似RequestInterceptor一样,增加一个配置类就可以,不需要每个接口做额外的判断?
...全文
8858 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
程序员周瑜 2020-07-09
  • 打赏
  • 举报
回复
问题已解决。 都怪基础知识不扎实,东抄西抄的。都忘记了一开始写过一个OkHttp的配置类。在里面写直接配置了addInterceptor

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@Slf4j
public class FeignClientConfig {

    private OkHttpClient okHttpClient;

    //注入okhttp
    @Bean
    public okhttp3.OkHttpClient okHttpClient(OkHttpClientFactory okHttpClientFactory,
                                             FeignHttpClientProperties httpClientProperties) {
        this.okHttpClient = okHttpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation()).connectTimeout(httpClientProperties.getConnectionTimeout(),TimeUnit.SECONDS)
                .followRedirects(httpClientProperties.isFollowRedirects())
                .addInterceptor(new OkHttpInterceptor())
                .build();
        return this.okHttpClient;
    }
}
上面这个配置增加拦截器时,直接new了OkHttpInterceptor,并没有让这个拦截器提前加载,所以重新定义一个Bean,让拦截器提前加载,addInterceptor时传入这个Bean就行了。

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
@Slf4j
public class FeignClientConfig {

    private OkHttpClient okHttpClient;

    @Bean
    public OkHttpInterceptor okHttpInterceptor(){
        return new OkHttpInterceptor();
    }

    //注入okhttp
    @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;
    }
}
程序员周瑜 2020-07-09
  • 打赏
  • 举报
回复
参考各位指导,我使用okhttp,新增了一个OkhttpInterceptor,但无法注入对象。又google了一下,了解了拦截器是在Springcontext之前加载,就新建了一个继承自WebMvcConfigure的类,代码如下:

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Bean
    public OkHttpInterceptor okHttpInterceptor (){
        return new OkHttpInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(okHttpInterceptor()).addPathPatterns("/**").excludePathPatterns("/css/**")
        .excludePathPatterns("/images/**")
        .excludePathPatterns("/js/**")
        .excludePathPatterns("/fonts/**");
    }
}
启动后,仍然注入的对象都是null 附上拦截器的代码:

@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");
    }
}
aaaak_ 2020-07-06
  • 打赏
  • 举报
回复
楼上说的很全了 自定义 feign 的 client , 我一般用的 OkHttp ,进行拦截验证 ,我也写了一篇文章 你可以看看 https://blog.csdn.net/u010020726/article/details/107044658
RockeyCui 2020-07-06
  • 打赏
  • 举报
回复
参考
https://blog.csdn.net/u010277958/article/details/88730889
https://segmentfault.com/a/1190000009821815
https://www.yiibai.com/apache_httpclient/apache_httpclient_interceptors.html
RockeyCui 2020-07-06
  • 打赏
  • 举报
回复
先明确,你这个 token 是不是用户客户端的 token。
1.如果是的话那应该由用户重新登录获取新的 token,而不是应用程序自己处理。

2.如果不是用户 token 的话。自定义 feign 的 client 的时候可以加拦截器,请求返回都可以拦截。

OKhttp3 作为 feign 的 client ,拦截器如何写自行 google 吧,这里不多说了。

httpclient 作为 feign 的 client,如何注册拦截器同上类似,自行 google。

81,094

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧