为啥我在使用 RestTemplate 获取数据时总是得到 403? [复制]

Posted

技术标签:

【中文标题】为啥我在使用 RestTemplate 获取数据时总是得到 403? [复制]【英文标题】:Why do I always get 403 when fetching data with RestTemplate? [duplicate]为什么我在使用 RestTemplate 获取数据时总是得到 403? [复制] 【发布时间】:2017-12-08 21:18:59 【问题描述】:

我正在尝试获取数据,但总是得到403(Forbidden)RestTemplate

但是当我尝试org.apache.http.client.HttpClient 时,一切正常。我还可以在我的机器上使用 Postman 获取数据。

代码很简单,但我不知道哪里出了问题。

public Object get() 
        try 
            RestTemplate restTemplate = new RestTemplate();
            Object result = restTemplate.getForObject("https://api.hearthstonejson.com/v1/19776/enUS/cards.json", Object.class);
            return result;
         catch (Exception ex) 
            logger.error(ex.getMessage(), ex);
            return null;
        
    

编辑:附加 堆栈跟踪

org.springframework.web.client.HttpClientErrorException: 403 Forbidden
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:63)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:287)
    at com.brawlstone.metaservice.service.SyncService.get(SyncService.java:49)
    at com.brawlstone.metaservice.web.SyncController.getCards(SyncController.java:30)
    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:133)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:115)
    at org.springframework.boot.web.support.ErrorPageFilter.access$000(ErrorPageFilter.java:59)
    at org.springframework.boot.web.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:90)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:108)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2500)
    at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2489)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

【问题讨论】:

【参考方案1】:

尝试在您的请求中添加“User-Agent”标头。

将您的代码更改为:

try 
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
            headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
            HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);

            Object response = restTemplate.exchange("https://api.hearthstonejson.com/v1/19776/enUS/cards.json", HttpMethod.GET,entity,Object.class);

            System.out.println(response);
         catch (Exception ex) 
           ex.printStackTrace();

        

【讨论】:

有效!但是为什么我可以通过“curl -X GET api.hearthstonejson.com/v1/19776/enUS/cards.json”获取数据呢?命令中没有用户代理。 从命令行尝试“curl -v api.hearthstonejson.com/v1/19776/enUS/cards.json”,你可以看到完整的标题列表和其他信息。可以看到“User-Agent: curl/7.52.1”。 您有关于此解决方案的一些文档/说明吗? @user7294900 这里给出了解释:***.com/questions/13670692/…【参考方案2】:

您正在尝试访问 https 而不配置 RestTemplate 以使用任何 SSL 证书进行请求

尝试使用RestTemplate的以下配置

CloseableHttpClient httpClient = HttpClients.custom()
                    .setSSLHostnameVerifier(new NoopHostnameVerifier())
                    .build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);
Object result = restTemplate.getForObject("https://api.hearthstonejson.com/v1/19776/enUS/cards.json", Object.class);
....

【讨论】:

它有效!谢谢!但是当我将 url 更改为“api.github.com”时,我删除了有关 ssl 的配置,我仍然能够成功获得结果。为什么会有差异? 我认为 github api 服务器可以选择接受没有 SSL/TLS 握手的请求,但 api.hearthstonejson 服务器没有。 实际上,这是一种不好的做法。这段代码告诉 HTTP 客户端信任每个证书,因此失去了一些 https 的感觉。这就是为什么中间人可以轻松拦截您的通信而您不会知道的原因。 它有效。但我添加了 'CloseableHttpClient httpClient = HttpClients.custom() .setSSLHostnameVerifier(NoopH​​ostnameVerifier.INSTANCE) .build()' 使用 httpClient 4.4v 这应该是被接受的有效答案!

以上是关于为啥我在使用 RestTemplate 获取数据时总是得到 403? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥基本身份验证总是使用 restTemplate 给出错误 403?

使用resttemplate访问时,如何使端点仅接受springboot中启用@crossorigin的uri?为啥我没有收到 cors 错误? [复制]

为啥 RestTemplate 不将响应表示绑定到 PagedResources?

为啥我在使用 useEffect 从区块链获取数据时会得到一系列 Promise?

请问使用RestTemplate请求远程接口获取对象数据时,服务端的该对象需不需要实现Serializable接口,求解释

为啥 Spring RestTemplate 在 Spring 中默认不是 Bean?