2017-12-21 6 views
1

私は、次のシグネチャを持つ私の春のブートアプリケーション(バージョン1.5.9.RELEASE)にRESTエンドポイントを持っている:ステータスコードが9xxのリソースを取得するためにRestTemplateを使用すると、ストリームが閉じられるのはなぜですか?

@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) 

私は問題を引き起こすことができるものは考えを持っていない、誰も私のためのヒントがありますか?

エンドポイントは、ステータステキスト「ユーザー名が既に存在します」を含む911応答が受信された郵便番号を介して到達可能です。

+0

パラメータとしてPOSTメソッドを指定してもよろしいですか?あなたのスタックトレースから:PUT要求のI/Oエラー –

+0

本当にスタックトレースは、まったく同じエラーを経験するPUTメソッドからのものです。 – user2035039

+0

なぜあなたは@ExceptionHandler(Exception.class)を処理​​しなかったのですか? –

答えて

0

org.springframework.web.client.ResponseErrorHandlerを実装して、残りのテンプレートに設定します。あなたは、エラー処理ロジックを実装する必要があります秒1で

/** 
    * 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

Iは、(春ブーツの同じバージョンの)同じ問題を経験し、それを修正するために、私はコンテンツを削除し、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(); 
} 

実際にコンテンツを送信する必要がある場合は間違いありません。

関連する問題