Spring Boot中RestTemplate调用API遇403 Forbidden(error code:1010)求助
Spring Boot RestTemplate调用API时403 Forbidden(错误码1010)问题解决
问题描述
使用Spring Boot的RestTemplate调用RapidAPI上的新冠数据接口时,持续收到403 Forbidden错误,错误码为1010。
相关代码
Country.java(响应实体类)
@NoArgsConstructor @Getter public class Country { private String name; private double iso_code; @Override public String toString() { return "Name: " + name + "\nIso Code: " + iso_code; } }
CountryRestClient.java(API调用客户端)
@Component public class CountryRestClient { private static final String url = "https://vaccovid-coronavirus-vaccine-and-treatment-tracker.p.rapidapi.com/api/npm-covid-data/countries-name-ordered"; private static final String apiKeyName = "X-RapidAPI-Key"; private static final String apiKeyValue = "42f0727d22msh9d"; private static final String hostName = "X-RapidAPI-Host"; private static final String hostValue = "vaccovid-coronavirus-vaccine-and-treatment-tracker.p.rapidapi.com"; RestTemplate restTemplate; public CountryRestClient(RestTemplateBuilder restTemplateBuilder) { restTemplate = restTemplateBuilder.build(); } public Country getCountry() { Country country = null; try { URI uri = new URI(url); HttpHeaders headers = new HttpHeaders(); headers.set(apiKeyName, apiKeyValue); headers.set(hostName, hostValue); headers.setContentType(MediaType.APPLICATION_JSON); headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); HttpEntity<String> request = new HttpEntity<>(headers); ResponseEntity<Country[]> countryEntity = restTemplate.exchange(uri, HttpMethod.GET, request, Country[].class); country = countryEntity.getBody()[0]; System.out.println("Name:" + country.getName() + "\nISO: " + country.getIso_code()); } catch (URISyntaxException e) { e.printStackTrace(); } return country; } }
CountryController.java(接口暴露层)
@RestController public class CountryController { @GetMapping("/countries") public Country getCountries() { return new CountryRestClient(new RestTemplateBuilder()).getCountry(); } }
错误栈信息
**Whitelabel Error Page** This application has no explicit mapping for /error, so you are seeing this as a fallback. Thu Sep 08 23:10:25 EDT 2022 There was an unexpected error (type=Internal Server Error, status=500). 403 Forbidden: "error code: 1010" org.springframework.web.client.HttpClientErrorException$Forbidden: 403 Forbidden: "error code: 1010" at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:109) at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:168) at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:122) at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:819) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:777) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:751) at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:621) at com.thymeleafdemo.client.CountryRestClient.getCountries(CountryRestClient.java:49) at com.thymeleafdemo.controller.CountryController.getCountries(CountryController.java:15) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1070) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:890) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:750)
排查与解决步骤
1. 检查API Key的有效性与完整性
- 当前使用的
apiKeyValue是截断状态(42f0727d22msh9d),RapidAPI的合法Key长度更长,需登录RapidAPI账号进入对应API的控制台,复制完整的API Key替换现有值。 - 确认API Key未过期,且账号在目标API上有剩余调用配额(免费版存在调用次数限制)。
2. 清理不必要的请求头
- GET请求无需设置
Content-Type头(无请求体),移除headers.setContentType(MediaType.APPLICATION_JSON);这一行,避免冗余头信息干扰接口验证。
3. 修正实体类字段类型
- 接口返回的
iso_code是字符串格式(如"US"、"CN"),但当前Country类中定义为double,会导致反序列化失败。将private double iso_code;修改为private String iso_code;。
4. 修复Spring依赖注入逻辑
CountryRestClient已标注@Component,但CountryController中直接实例化对象,未使用Spring容器管理的实例,不符合最佳实践。改为构造方法注入:
@RestController public class CountryController { private final CountryRestClient countryRestClient; public CountryController(CountryRestClient countryRestClient) { this.countryRestClient = countryRestClient; } @GetMapping("/countries") public Country getCountries() { return countryRestClient.getCountry(); } }
5. 添加错误详情日志
- 给
RestTemplate添加自定义错误处理器,便于查看API返回的完整错误信息:
public CountryRestClient(RestTemplateBuilder restTemplateBuilder) { restTemplate = restTemplateBuilder .errorHandler(new DefaultResponseErrorHandler() { @Override public void handleError(ClientHttpResponse response) throws IOException { String responseBody = new String(response.getBody().readAllBytes(), StandardCharsets.UTF_8); System.err.println("API错误响应:" + responseBody); super.handleError(response); } }) .build(); }
内容的提问来源于stack exchange,提问作者Ricky Patel
相关产品推荐
相关产品推荐

