码代码的时候遇到个问题,去请求某个服务方的时候,需要在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容器中初始化的顺序!!!

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

被折叠的 条评论
为什么被折叠?



