2017-12-21 3 views
1

나는 다음과 같은 서명 나의 봄 부팅 응용 프로그램 (버전 1.5.9.RELEASE)에서 REST 엔드 포인트가 있습니다RestTemplate을 사용하여 9xx 상태 코드가있는 리소스를 검색 할 때 스트림이 닫히는 이유는 무엇입니까?

@RequestMapping(value = "/users", method = RequestMethod.POST) throws UsernameExistsException, EmailExistsException 
public UserProxy addUser(@RequestBody UserProxy userProxy) { 
    ... 
} 

예외가 @ControllerAdvice 주석 클래스에 @ExceptionHandler 주석의 방법으로 처리됩니다

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://192.168.99.100:8080/users": stream is closed; nested exception is java.io.IOException: stream is closed 
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:673) 
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:620) 
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:387) 
at com.cheetahrunner.users.mongo.client.UsersClient.createUser(UsersClient.java:44) 
at com.cheetahrunner.users.UsersServiceTest.addUser(UsersServiceTest.java:102) 
at com.cheetahrunner.users.UsersServiceTest.testAddRemoveUser(UsersServiceTest.java:47) 
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.base/java.lang.reflect.Method.invoke(Method.java:564) 
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) 
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
15:37:44.517 [main] DEBUG org.springframework.web.client.RestTemplate - POST request for "http://192.168.99.100:8080/users" resulted in 911 (null) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153) 
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128) 
    at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203) 
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155) 
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103) 
Caused by: java.io.IOException: stream is closed 
    at java.base/sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.ensureOpen(HttpURLConnection.java:3417) 
    at java.base/sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3422) 
    at java.base/java.io.FilterInputStream.read(FilterInputStream.java:83) 
    at java.base/java.io.PushbackInputStream.read(PushbackInputStream.java:136) 
    at org.springframework.web.client.MessageBodyClientHttpResponseWrapper.hasEmptyMessageBody(MessageBodyClientHttpResponseWrapper.java:102) 
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:82) 
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:662) 
    ... 30 more 
: 엔드 포인트에 액세스 할 때 예외가 슬로우 될 때
@EnableWebMvc 
@ControllerAdvice 
public class ControllerExceptionHandler { 

    @ExceptionHandler(EmailExistsException.class) 
    public ResponseEntity<String> handleEmailExistsException() { 
    return ResponseEntity 
      .status(UsersStatusCodes.EMAIL_EXISTS) // status code 912 
      .body("Email already exists"); 
    } 

    @ExceptionHandler(UsernameExistsException.class) 
    public ResponseEntity<String> handleUsernameExistsException() { 
    return ResponseEntity 
      .status(UsersStatusCodes.USERNAME_EXISTS) // status code 911 
      .body("Username already exists"); 
    } 
} 

그러나, 나는 클라이언트 측에서 다음과 같은 예외를 검색

rest.exchange(host + "/users", HttpMethod.POST, new HttpEntity<UserProxy>(user), UserProxy.class) 

나는 누군가가 나를 위해 힌트를 않는 문제가 발생할 수 무슨 생각이 없어 :

엔드 포인트에 액세스하는 데 사용되는 코드는 다음과 같다?

"Username already exists"라는 상태 텍스트가있는 911 응답이 수신되는 Postman을 통해 끝점에 도달 할 수 있습니다.

+0

POST 메서드를 매개 변수로 지정 하시겠습니까? 귀하의 스택 추적에서 : PUT 요청에 입출력 오류 –

+0

죄송합니다. 실제로 동일한 오류가 발생하는 PUT 메서드에서 스택 추적입니다. – user2035039

+0

@ExceptionHandler (Exception.class)를 처리하지 않은 이유는 무엇입니까? –

답변

0

org.springframework.web.client.ResponseErrorHandler를 구현하고 나머지 템플릿으로 설정 : 당신은 오류 처리 로직을 구현해야합니다 두 번째에서

/** 
    * Indicate whether the given response has any errors. 
    * <p>Implementations will typically inspect the 
    * {@link ClientHttpResponse#getStatusCode() HttpStatus} of the response. 
    * @param response the response to inspect 
    * @return {@code true} if the response has an error; {@code false} otherwise 
    * @throws IOException in case of I/O errors 
    */ 
    boolean hasError(ClientHttpResponse response) throws IOException; 

    /** 
    * Handle the error in the given response. 
    * <p>This method is only called when {@link #hasError(ClientHttpResponse)} 
    * has returned {@code true}. 
    * @param response the response with the error 
    * @throws IOException in case of I/O errors 
    */ 
    void handleError(ClientHttpResponse response) throws IOException; 

:

rest.setErrorHandler(errorHandler); 

ResponseErrorHandler 2 가지 방법이있다. 나는 (봄 부팅 동일한 버전) 같은 문제가 발생

@Override 
public boolean hasError(ClientHttpResponse response) throws IOException { 
    HttpStatus code = response.getStatusCode(); 
    return code != HttpStatus.OK && code != HttpStatus.NO_CONTENT && code != HttpStatus.NOT_MODIFIED; 
} 
0

하고 내가하는 콘텐츠를 삭제 수정하고 0의 콘텐츠 길이 헤더를 설정 :

첫 번째는 같아야합니다

@ExceptionHandler(NotFoundException.class) 
public ResponseEntity<Object> applicationFormNotFound() { 
    final HttpHeaders headers = new HttpHeaders(); 
    headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); 
    headers.add(HttpHeaders.CONTENT_LENGTH, "0"); 
    return ResponseEntity.status(HttpStatus.NOT_FOUND) 
      .headers(headers) 
      .build(); 
} 

실제로 콘텐츠를 전송해야하는 경우에는별로 도움이되지 않습니다.

관련 문제