Spring Boot应用无法从.env读取API密钥,请求报错如何修复?
解决APILayer货币兑换API调用的两个核心问题
一、API密钥读取失败(始终使用default-key)
问题原因
- Spring Boot 2.4+版本默认不会自动加载
.env文件,导致配置未被读取; Constants类使用静态变量结合@Value注入,存在初始化顺序问题,容易导致注入值未生效。
解决方案
1. 确保.env文件被正确加载
- 在项目的
pom.xml(Maven)或build.gradle(Gradle)中添加spring-boot-starter-cloud-context依赖,让Spring自动识别.env文件; - 或者在Spring Boot主启动类上添加
@PropertySource("classpath:.env")注解,手动指定加载.env配置(注意.env需放在src/main/resources目录下)。
2. 重构配置读取逻辑(推荐)
弃用静态变量的方式,改用@ConfigurationProperties绑定配置,更符合Spring规范:
@Component @ConfigurationProperties(prefix = "exchange-api") public class ApiProperties { private String apiUrl; private String apiKey; private String cacheName; private Integer apiCallLimit; // 生成getter和setter方法 }
然后在RateService中注入ApiProperties替代静态变量:
@Service public class RateService { private final ApiProperties apiProperties; private final RestTemplate restTemplate; private final RateRepository rateRepository; // 构造方法注入 public RateService(ApiProperties apiProperties, RestTemplate restTemplate, RateRepository rateRepository) { this.apiProperties = apiProperties; this.restTemplate = restTemplate; this.rateRepository = rateRepository; } private RateEntity saveRatesFromApi(LocalDate rateDate, EnumCurrency base, List<EnumCurrency> targets) { log.info("ExchangeService | saveRatesFromApi is called"); HttpHeaders headers = new HttpHeaders(); // 使用配置类中的apiKey headers.add("apikey", apiProperties.getApiKey()); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); final HttpEntity<String> headersEntity = new HttpEntity<>(headers); String url = getExchangeUrl(rateDate, base, targets); ResponseEntity<RateResponse> responseEntity = restTemplate.exchange(url, HttpMethod.GET, headersEntity, RateResponse.class); RateResponse rates = responseEntity.getBody(); RateEntity entity = convert(rates); entity.setDate(rateDate); return rateRepository.save(entity); } private String getExchangeUrl(LocalDate rateDate, EnumCurrency base, List<EnumCurrency> targets) { String symbols = String.join("%2C", targets.stream().map(EnumCurrency::name).toArray(String[]::new)); // 使用配置类中的apiUrl return apiProperties.getApiUrl() + rateDate + "?symbols=" + symbols + "&base=" + base; } }
二、Jackson反序列化错误(Unrecognized field "message")
问题原因
APILayer返回的错误响应包含message字段,但自定义的RestTemplateError类未定义该字段,且未配置Jackson忽略未知属性,导致反序列化失败。
解决方案
方式1:添加message字段到RestTemplateError
public class RestTemplateError { private String error; private int status; private String path; private long timestamp; private String message; // 新增字段匹配API返回 // 生成对应getter和setter }
方式2:配置Jackson忽略未知字段
在RestTemplateError类上添加@JsonIgnoreProperties注解,让Jackson忽略未定义的字段:
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) public class RestTemplateError { private String error; private int status; private String path; private long timestamp; // 生成getter和setter }
可选:完善RestTemplate错误处理
配置RestTemplate的错误处理器,确保API返回错误状态码时能正确解析错误信息:
@Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { @Override protected boolean hasError(HttpStatus statusCode) { return statusCode.is4xxClientError() || statusCode.is5xxServerError(); } @Override public void handleError(ClientHttpResponse response) throws IOException { ObjectMapper mapper = new ObjectMapper(); RestTemplateError error = mapper.readValue(response.getBody(), RestTemplateError.class); throw new RuntimeException(error.getMessage() != null ? error.getMessage() : error.getError(), response.getStatusCode()); } }); return restTemplate; }
内容的提问来源于stack exchange,提问作者Sercan Noyan Germiyanoğlu
相关产品推荐
相关产品推荐

