获取 java.net.HttpRetryException:由于服务器身份验证,无法在流模式下重试

Getting java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode

我已经为创建新用户创建了一个测试:

private static String USERS_ENDPOINT = "http://localhost:8080/users/";
private static String GROUPS_ENDPOINT = "http://localhost:8080/groups/";

@Test
@DirtiesContext(classMode = ClassMode.BEFORE_EACH_TEST_METHOD)
public void whenCreateAppUser() {

    AppUser appUser = new AppUser();
    appUser.setUsername("test@example.com");
    appUser.setPassword("password");

    // Throws java.net.HttpRetryException
    template.postForEntity(USERS_ENDPOINT, appUser, AppUser.class);

    ResponseEntity<AppUser> appUserResponse = template.getForEntity(USERS_ENDPOINT + "1/", AppUser.class);

    assertEquals("Username is incorrect. AppUser not created?",
            appUser.getUsername(), appUserResponse.getBody().getUsername());
}

但是,出于某种原因我得到:

Caused by: java.net.HttpRetryException: cannot retry due to server authentication, in streaming mode
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1692)
    at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1492)
    at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
    at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:55)
    at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:49)
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:735)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:700)
    ... 34 more

来电

template.postForEntity(USERS_ENDPOINT, appUser, AppUser.class);

我实际上不知道我改变了什么,因为这曾经对我有用。知道是什么导致了这个问题吗?


我的 WebSecurity 设置是:

@Override
public void configure(WebSecurity web) throws Exception {

    final String[] SWAGGER_UI = {
            "/swagger-resources/**",
            "/swagger-ui.html",
            "/v2/api-docs",
            "/webjars/**"
    };

    web.ignoring().antMatchers("/pub/**", "/users")
            .antMatchers(SWAGGER_UI);
}

Spring 的 RestTemplate 和 Spring Boot 的 TestRestTemplate 默认情况下将在 JDK 的内部 HttpURLConnection 实现上,无法访问状态为 401 "Unauthorized".

的 HTTP 响应的 body

一个神奇的解决方案是将 Apache 的 HTTP 客户端包含到类路径中 — 例如使用 Maven:

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.5.6</version>
  <scope>test</scope>
</dependency>

在这种情况下,Spring(或 Spring 引导)将使用 Apache 的 HTTP 客户端,不会遇到问题。

另请参阅:https://github.com/spring-projects/spring-security-oauth/issues/441#issuecomment-92033542


P.S。我刚刚遇到了同样的问题:)

使用 Apache HttpComponents Client 库中的 HttpClient 解决了我的问题。

要使用 Apache HttpClient,您必须按以下方式配置 RestTemplate:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestClientConfig {

    @Bean
    public RestTemplate restTemplate() {
        var template = new RestTemplate();

        template.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

        return template;
    }

}

中的回答

另一种选择是:

SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setOutputStreaming(false);
return requestFactory;