原因
produces = "text/csv"
が設定されているのにJSONを返そうとしたことが原因でした。
状況
状況は以下の通りです。
実現したかったもの
- csvを返す(
produces = "text/csv"
を設定)エンドポイントを立てる - 集計エラー時はステータス400で、JSONにエラー内容を詰めて返す
実際には以下のようなアノテーションを付与していました。
@PostMapping(value = "[エンドポイント]", produces = "text/csv")
起きたこと
- エラー時にステータスが406になる
- エラー内容も空になる
- サーバーサイドでは
HttpMediaTypeNotAcceptableException
が発生する
対策
produces
の指定を無くせばOKでした。
@PostMapping(value = "[エンドポイント]")
produces
を指定しない場合場合はよしなに扱われるようなので、問題が出なければ指定しなくてもよいと思われます。
補足
動的かつ明示的に指定する必要がある場合、HttpServletResponse
を用いてレスポンスを直接書き込む方法が考えられます。
その場合は以下のようにして書けます。
@PostMapping(value = "/api/csv")
public void csv(HttpServletResponse response) {
String csv = // CSV取得処理;
response.setHeader(
"Content-Disposition",
"attachment;filename=\"" + /* ファイル名 */ + "\""
);
response.setCharacterEncoding("Shift-JIS");
response.setContentType("text/csv");
try (Writer writer = response.getWriter()) {
writer.write(csv);
} catch (IOException e) {
// エラー処理
}
}
感想
エラー処理はExceptionHandler
を用いて共通化していましたが、コントローラーで設定したproduces
がそこまで貫通してくると思わず原因特定に時間がかかってしまいました。
HttpMediaTypeNotAcceptableException
とは書いてあったんですが……。