feign请求拦截器中读取配置文件的问题

本文探讨了在使用Spring Boot与Feign进行API请求时,如何处理因环境变量配置导致的签名生成问题。作者分享了如何在Interceptor中正确读取环境变量并生成SHA256签名,以及解决初始化顺序问题的方法。

码代码的时候遇到个问题,去请求某个服务方的时候,需要在header里放签名进行校验,签名是通过SHA256算法生成的。sig的值和密钥及key有关,不同环境这些配置又不一样,所以就想到,把key和secret放在不同环境的配置文件中,这样直接去读就行。
拦截器的写法:

@Component
@Slf4j
public class LabelInterceptor implements RequestInterceptor {
    @Value("${key}")
    private String KEY;
    @Value("${secret}")
    private String SECRET;

    @Override
    public void apply(RequestTemplate requestTemplate) {
        requestTemplate.header("api_key",KEY);
        long time = Instant.now().getEpochSecond();
        String sig = DigestUtils.sha256Hex(KEY + SECRET + time);
        requestTemplate.header("sig",sig);
    }
}

feign配置:

@Configuration
@Slf4j
public class LabelFeignBuilder {

    @Bean(name = "labelFeign")
    public Feign.Builder getFeignBuilder() {
        return Feign.builder()
                .logLevel(Logger.Level.NONE)
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .logger(new Logger.ErrorLogger())
                .errorDecoder(errorDecoder())
                .options(getOptions())
                .requestInterceptor(new FeignHeaderInterceptor())
                .requestInterceptor(new LabelInterceptor())
                .client(apacheHttpClient());
    }

    @Bean
    public FeignErrorDecoder errorDecoder() {
        return new FeignErrorDecoder();
    }

    @Bean
    public Request.Options getOptions() {
        return new Request.Options(2, TimeUnit.SECONDS, 2, TimeUnit.SECONDS, true);
    }

    @Bean
    public ApacheHttpClient apacheHttpClient(){
        log.info("init feign httpclient configuration " );
        // 生成默认请求配置
        RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
        // 超时时间
        requestConfigBuilder.setSocketTimeout(2* 1000);
        // 连接时间
        requestConfigBuilder.setConnectTimeout(2* 1000);

        // 连接池获取的 超时时间
        requestConfigBuilder.setConnectionRequestTimeout(2*1000);


        RequestConfig defaultRequestConfig = requestConfigBuilder.build();
        // 连接池配置
        // 长连接保持30秒
        final PoolingHttpClientConnectionManager pollingConnectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.MILLISECONDS);
        // 总连接数
        pollingConnectionManager.setMaxTotal(5000);
        // 同路由的并发数
        pollingConnectionManager.setDefaultMaxPerRoute(1000);


        // httpclient 配置
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        // 保持长连接配置,需要在头添加Keep-Alive
        httpClientBuilder.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
        httpClientBuilder.setConnectionManager(pollingConnectionManager);
        httpClientBuilder.setDefaultRequestConfig(defaultRequestConfig);
        CloseableHttpClient client = httpClientBuilder.build();

        // 启动定时器,定时回收过期的连接
        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
        scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                log.debug("=====closeIdleConnections===");
                pollingConnectionManager.closeExpiredConnections();
                pollingConnectionManager.closeIdleConnections(5, TimeUnit.SECONDS);
            }
        }, 10 * 1000, 5 * 1000, TimeUnit.MILLISECONDS);
        log.info("===== Apache httpclient 初始化连接池===");

        return new ApacheHttpClient(client);
    }
}

乍一看写的没有任何问题,但是在请求的时候总是会报错sig过期,很不解,仔细查看调试后发现,在调用的时候,读取key和secret都没有读到,是null,所以签名生成的不对。
查了一下,发现是拦截器读取配置的时候,配置文件还未初始化,所以读取不到。如果在用拦截器的地方用@Bean注解,就可以解决。在feign配置文件中加上下边代码:


    @Bean
    public LabelInterceptor labelInterceptor(){
        return new LabelInterceptor();
    }

切记之后要关注不同文件在spring容器中初始化的顺序!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值