web-dev-qa-db-ja.com

404 Not Found例外に本文を追加する

REST JHipsterで生成されたAPIで、いくつかの404例外をスローしたいのですが、通常は

return new ResponseEntity<>(HttpStatus.NOT_FOUND);

実際には、xhrリクエストに対して404レスポンスが返されます。問題は、フロントサイドで、JHipsterが応答を解析することです。

angular.fromJson(result)

そして、404が実際の応答である場合、そのような結果は空であり、解析が失敗します。

マップされていないURIを指す場合は、コントローラーが/api/user(複数形に注意)にマップしている間に/api/usersと言ってみましょう。APIから取得した404には本体があります。

{
    "timestamp": "2016-04-25T18:33:19.947+0000",
    "status": 404,
    "error": "Not Found",
    "message": "No message available",
    "path": "/api/user/myuser/contact"
}

これは角度で正しく解析されます。

このようなボディを作成するにはどうすればよいですか?この例外は春にスローされますか、それともTomcatがスローしますか?

私はこれを試しました: Spring-MVCコントローラーのトリガー404? ですが、応答のパラメーターを設定できません。

13
luso

基本的な考え方


最初のオプションは、エラーオブジェクトを定義し、それらを404 Not Found本体として返すことです。次のようなもの:

Map<String, String> errors = ....;
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errors);

典型的なResponseEntityを返す代わりに、404 Not Foundに解決されるExceptionをスローできます。次のようなNotFoundExceptionがあるとします。

@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException {}

次に、この例外をコントローラーでスローすると、次のようになります。

{  
   "timestamp":1461621047967,
   "status":404,
   "error":"Not Found",
   "exception":"NotFoundException",
   "message":"No message available",
   "path":"/greet"
}

メッセージおよび本文の他の部分をカスタマイズする場合は、ExceptionHandlerNotFoundExceptionを定義する必要があります。

例外階層の紹介


RESTful APIを作成していて、さまざまな例外ケースに異なるエラーコードおよびエラーメッセージを設定したい場合は、それらのケースを表す例外の階層を作成し、メッセージを抽出できます。そしてそれぞれからのコード。

たとえば、コントローラがスローする他のすべての例外のスーパークラスであるAPIExceptionなどの例外を導入できます。このクラスは、次のようなコード/メッセージのペアを定義します。

public class APIException extends RuntimeException {
    private final int code;
    private final String message;

    APIException(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int code() {
        return code;
    }

    public String message() {
        return message;
    }
}

例外の性質に応じた各サブクラスは、このペアに適切な値を提供できます。たとえば、InvalidStateExceptionを使用できます。

@ResponseStatus(code = HttpStatus.BAD_REQUEST)
public class InvalidStateException extends APIException {
    public InvalidStateException() {
        super(1, "Application is in invalid state");
    }
}

またはその悪名高い見つからないもの:

@ResponseStatus(code = HttpStatus.NOT_FOUND)
public class SomethingNotFoundException extends APIException {
    public SomethingNotFoundException() {
        super(2, "Couldn't find something!");
    }
}

次に、これらの例外をキャッチして意味のあるJSON表現に変換するErrorControllerを定義する必要があります。そのエラーコントローラは次のようになります。

@RestController
public class APIExceptionHandler extends AbstractErrorController {
    private static final String ERROR_PATH = "/error";
    private final ErrorAttributes errorAttributes;

    @Autowired
    public APIExceptionHandler(ErrorAttributes errorAttributes) {
        super(errorAttributes);
        this.errorAttributes = errorAttributes;
    }

    @RequestMapping(path = ERROR_PATH)
    public ResponseEntity<?> handleError(HttpServletRequest request) {
        HttpStatus status = getStatus(request);

        Map<String, Object> errors = getErrorAttributes(request, false);
        getApiException(request).ifPresent(apiError -> {
            errors.put("message" , apiError.message());
            errors.put("code", apiError.code());
        });
        // If you don't want to expose exception!
        errors.remove("exception");


        return ResponseEntity.status(status).body(errors);
    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

    private Optional<APIException> getApiException(HttpServletRequest request) {
        RequestAttributes attributes = new ServletRequestAttributes(request);
        Throwable throwable = errorAttributes.getError(attributes);
        if (throwable instanceof APIException) {
            APIException exception = (APIException) throwable;
            return Optional.of(exception);
        }

        return Optional.empty();
    }
}

したがって、SomethingNotFoundExceptionをスローすると、返されるJSONは次のようになります。

{  
   "timestamp":1461621047967,
   "status":404,
   "error":"Not Found",
   "message":"Couldn't find something!",
   "code": 2,
   "path":"/greet"
}
13
Ali Dehghani

メッセージを返すか、エラーコードでテストしたい場合は、これを行うことができると思います

@ResponseBody
public ResponseEntity somthing() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
return new ResponseEntity<>(new Gson().toJson("hello this is my message"), headers, HttpStatus.NOT_FOUND);
}
0
AbdusSalam