2017-12-15 2 views
2

私はtext/csvを返すメソッドを持つコントローラを持っています。正常な成功の場合は正常に動作しますが、例外がスローされ、ヘッダがAccept: text/csvの場合、406応答が返されます。例えば:406テキスト/ csvの受け入れヘッダを持つSpringコントローラで例外がスローされたとき

@RequestMapping(value = "/foo", method = RequestMethod.GET, produces = "text/csv") 
public String getCsv() { 
    throw new IllegalArgumentException(); 
} 

これは(spring-boot-starter-web-servicesをインポート、Mavenプロジェクト)完全バニラスプリングブートアプリケーションである、上記の方法とコントローラが、何からなります。

私は、例外がフレームワークによるJSONエラー応答に変換されているためです。 produces属性を削除してAccept: */*を送信すると、例外のJSON表現が取得されます。明らかにJSONはtext/csvではないため、406(許容できない)応答です。

{ 
    "timestamp": 1513465445542, 
    "info": { 
     "method": "GET", 
     "path": "/foo", 
     "headers": { 
      "request": { 
       "host": "localhost:8080", 
       "user-agent": "curl/7.47.0", 
       "accept": "text/csv" 
      }, 
      "response": { 
       "X-Application-Context": "application", 
       "status": "500" 
      } 
     }, 
     "timeTaken": "1" 
    } 
} 
:私は私のSpringアプリケーションで /traceエンドポイントを見れば、私は別の何かを参照して、興味深いことに、しかし

curl -v http://localhost:8080/foo -H 'accept: text/csv' 
* Trying 127.0.0.1... 
* Connected to localhost (127.0.0.1) port 8080 (#0) 
> GET /foo HTTP/1.1 
> Host: localhost:8080 
> User-Agent: curl/7.47.0 
> accept: text/csv 
> 
< HTTP/1.1 406 
< X-Application-Context: application 
< Content-Length: 0 
< Date: Sat, 16 Dec 2017 23:04:05 GMT 
< 
* Connection #0 to host localhost left intact 

:ここ

は、問題を示すカールリクエスト/レスポンスの例です

だから、Springはそれが500を返すと思っていますが、それがカールすると、それは406です。私はPostManから私の要求を送ると全く同じことが分かります。

私はそれがクライアントではないと想定していますので、私の最高の推測はTomcatがそれをやっているということです。それを止める方法はありますか?それとも私が行方不明になっている他の可能性がありますか?

答えて

3

====オリジナル回答(期待される動作を説明する)====

Acceptヘッダは、クライアントがサーバがが返されると想定し、フォーマットタイプを指定します。これに差があれば、HTTP 406 - Not Acceptableエラーになります。ただし、このエラーは操作が失敗したことを意味するものではありませんが、指定された形式でクライアントの期待が失敗したことを示します。

あなたのケースではAcceptヘッダがtext/csvを運ぶが、明確な不一致があるため、サーバーがapplication/json、これ406エラーで応答します。

この動作を修正するには、サーバー/スプリングの最後に変更する必要はありません。代わりにクライアントはapplication/json,text/csvとして値を持つAcceptヘッダーの送信を開始する必要があります。これにより、クライアントは両方のフォーマットを期待し、有効/エラー応答の場合にサポートします。

詳細はhereを参照してください。

編集2017年12月22日

が観察された行動は、春のチームhereによってバグとして確認されています。既知の回避策はまだありません。

編集2018年1月4日

我々は@RestControllerAdviceHandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE要求属性を削除する必要が回避策としてSpring JIRA commentsで述べたように。コードは

休憩コントローラアドバイス

@RestControllerAdvice 
public class ExampleControllerAdvice { 

    @ExceptionHandler(value = Exception.class) 
    public ResponseEntity<ErrorResponse> handleException(HttpServletRequest request, Exception e) { 
     ErrorResponse response = new ErrorResponse(); 
     response.setErrorMsg("Server error"); 
     response.setErrorCode("ERROR007"); 
     request.removeAttribute(
        HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); 

     return new ResponseEntity<ErrorResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR); 
    } 
} 

はErrorResponse

public class ErrorResponse { 

    private String errorCode; 
    private String errorMsg; 

    public String getErrorCode() { 
     return errorCode; 
    } 

    public void setErrorCode(String errorCode) { 
     this.errorCode = errorCode; 
    } 

    public String getErrorMsg() { 
     return errorMsg; 
    } 

    public void setErrorMsg(String errorMsg) { 
     this.errorMsg = errorMsg; 
    } 

} 
+1

オクラホマので、私は問題を再現することができた以下のようになります。表示される500エラーは、コントローラコードから送出された 'IllegalArgumentException'のためです。 406は、スプリングがエラー応答のための適切なメッセージコンバータを見つけることができないためです。私はDEBUGログを春に有効にし、この例外をorg.springframework.web.HttpMediaTypeNotAcceptableException:ログに受け入れ可能な表現を見つけることができませんでした。また、追加のメッセージコンバータを設定しようとしましたが、まだブレークスルーはありません。しかし、試し続けます。 –

+0

優れている、まあまあ私の頭の中に浮かんでいる漠然とした考えのように聞こえるが、はるかに簡潔に、実際の証拠で表現されている:)メッセージコンバータが正しい解決策であるかどうかわからない。 application/jsonであり、Acceptヘッダーは無視されます。私はあなたが元々、クライアントが詳細なエラーメッセージを得るために 'text/CSV、application/json'を要求しているべきだと思っていますが、Springはどちらのタイプも受け入れるという事実を尊重していないようです。 – DaveyDaveDave

+1

私は[バネフォーラムのバグ](https://jira.spring.io/browse/SPR-16318)を作成しました。そこからの応答/解決を得ることを願っています。 –

関連する問題