【发布时间】:2020-12-29 03:26:47
【问题描述】:
我已经将一个 Spring 应用程序连接到一个 React 前端,我需要在其中显示我的自定义异常。自定义异常在 Spring 中完美运行,但前端 (React) 只收到错误代码 (417) 而没有其他任何内容。
我已经确定问题在于异常没有以 JSON 格式返回,因为当我使用 Postman 时错误消息是完整显示的,而不是 JSON 格式。
我的研究表明,由于我使用的是@RestController(用于我的主控制器)和@ControllerAdvice(用于我的自定义异常处理程序),它应该以 JSON 格式返回。我还尝试将 ResponseBody bean 添加到特定函数,但这也无济于事。
Controller.java
package com.chess.controller;
import com.chess.board.*;
import com.chess.gameflow.Game;
import com.chess.gameflow.Move;
import com.chess.gameflow.Player;
import com.chess.gameflow.Status;
import com.chess.models.requests.BoardRequest;
import com.chess.models.requests.PlayerRequest;
import com.chess.models.requests.StatusRequest;
import com.chess.models.responses.MovesResponse;
import com.chess.models.responses.Response;
import com.chess.models.responses.StatusResponse;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@CrossOrigin(origins= "http://localhost:3000", maxAge=7200)
@RestController
@RequestMapping("/game")
public class Controller {
Game game;
Board board = Board.boardConstructor();
@PostMapping("/players")
public List<Response> createPlayer(@RequestBody PlayerRequest request){
game = new Game(request.getName1(), request.getName2());
List<Response> returnValue = board.returnBoard();
Player player1= Game.players[0];
StatusResponse status = new StatusResponse(Status.isActive(), Status.isCheck(), player1);
returnValue.add(status);
return returnValue;
}
@PostMapping
public List<Response> makeMove(@RequestBody BoardRequest boardRequest){
StatusResponse status = Game.run(boardRequest);
List<Response> returnValue = board.returnBoard();
returnValue.add(status);
return returnValue;
}
@PostMapping("/end")
public StatusResponse endGame(@RequestBody StatusRequest statusRequest){
Status.setActive(false);
Board board = Board.boardConstructor();
board.generateBoard();
if (statusRequest.isForfeit()){
StatusResponse statusResponse = new StatusResponse(statusRequest.getPlayerName() + " declares defeat! Game Over!");
return statusResponse;
}
StatusResponse statusResponse = new StatusResponse("We have a draw! Good Game!");
return statusResponse;
}
@GetMapping("/moves")
public MovesResponse displayMoves(){
MovesResponse movesResponse = new MovesResponse(Move.returnMoveMessages());
return movesResponse;
}
}
CustomExceptionsHandler.java
package com.chess.exceptions;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
@ControllerAdvice
public class CustomExceptionsHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(value = InvalidMoveException.class)
@ResponseBody //this line shouldn't be necessary as I am using a RestController but I added it anyways in one of my futile attempts and I don't think it should hurt
protected ResponseEntity<Object> resolveInvalidMove(InvalidMoveException e, WebRequest req) throws Exception {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.EXPECTATION_FAILED.value(),
HttpStatus.EXPECTATION_FAILED.getReasonPhrase(),
e.getMessage(),
req.getDescription(true));
return handleExceptionInternal(e, errorResponse.toString(), new HttpHeaders(), HttpStatus.EXPECTATION_FAILED, req);
@ExceptionHandler(value = MustDefeatCheckException.class)
protected ResponseEntity<Object> resolveCheckStatus(MustDefeatCheckException e, WebRequest req){
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.EXPECTATION_FAILED.value(),
HttpStatus.EXPECTATION_FAILED.getReasonPhrase(),
e.getMessage(),
req.getDescription(true));
return handleExceptionInternal(e, errorResponse, new HttpHeaders(), HttpStatus.EXPECTATION_FAILED, req);
}
}
ErrorResponse.java
package com.chess.exceptions;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "error")
public class ErrorResponse {
private int status;
private String errReason;
private String errMessage;
private String path;
public ErrorResponse(int status, String errReason, String errMessage, String path) {
this.status = status;
this.errReason = errReason;
this.errMessage = errMessage;
this.path = path;
}
@Override
public String toString(){
return "Status Code: " + status + " " + errReason + " Message: " + errMessage + " at " + path;
}
}
InvalidMoveException.java
package com.chess.exceptions;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.EXPECTATION_FAILED, reason="Invalid Move")
public class InvalidMoveException extends RuntimeException {
public InvalidMoveException(String msg){ super(msg); }
}
【问题讨论】: