iT邦幫忙

2021 iThome 鐵人賽

1
自我挑戰組

Angular+Spring Boot API 處理股市資料系列 第 32

StockAPI-錯誤訊息處理 (Day32)

先前我們建立的StockAPI在解析token字串時,並沒有針對解析錯誤的情況去做錯誤處理,所以如果簽證過期的話就會出現

https://ithelp.ithome.com.tw/upload/images/20211024/20138857NtxiFROki5.png

在錯誤處理方面,Spring Boot上面有提供API的錯誤處理,

還記得我們之前實作JWTCheckFilter的範例嗎?

由於我們此次的錯誤是從filter拋出的,因此只透過@RestControllerAdvice

和@ExceptionHandler是捕捉不到錯誤的,原因是ControllerAdvice只能捕捉到從有@Controller這個註解類拋出的錯誤,而從更外層的filter產生的錯誤以下提供兩種思路去捕捉錯誤

1.透過實作ErrorController(就是會出現white label頁的控制類),使filter拋出的錯誤重新回到
@Controller控制類的底下,ControllerAdvice就可以捕捉

2.在filter用try-catch捕捉錯誤後直接寫出結果

在這邊我們實作第一種方法


先實作ErrorController類


package com.stockAPI.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class TokenErrorControllerImpl implements ErrorController {

	 @RequestMapping("/error")
	  public void handleError(HttpServletRequest request) throws Throwable {
	//只要遇到exception就直接拋出
	    if (request.getAttribute("javax.servlet.error.exception") != null) {
	      throw (Throwable) request.getAttribute("javax.servlet.error.exception");
	    }
	  }
	
}

@RestControllerAdvice -BaseHandler


package com.stockAPI.exceptionHandler;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.stockAPI.enumsave.TokenEnum;
import com.stockAPI.exception.TokenException;
import com.stockAPI.model.APIReturnObject;

import io.jsonwebtoken.ExpiredJwtException;

@RestControllerAdvice
public class BaseHandler {

	static Logger logger = LogManager.getLogger();

	// 登入驗證錯誤
	@ExceptionHandler(UsernameNotFoundException.class)
	public ResponseEntity<APIReturnObject> usernameNotFoundException(UsernameNotFoundException e) {
		APIReturnObject aPIReturnObject = new APIReturnObject();
		aPIReturnObject.setMessage(e.getMessage());
		return new ResponseEntity<APIReturnObject>(aPIReturnObject, HttpStatus.FORBIDDEN);
	}

	// token過期
	@ExceptionHandler(ExpiredJwtException.class)
	public ResponseEntity<APIReturnObject> expiredJwtException(ExpiredJwtException e) {
		APIReturnObject aPIReturnObject = new APIReturnObject();
		aPIReturnObject.setMessage(TokenEnum.TOKEN_ERROR_EXPIRED.getMessage());
		return new ResponseEntity<APIReturnObject>(aPIReturnObject, HttpStatus.REQUEST_TIMEOUT);
	}

	// 身分驗證有誤
	@ExceptionHandler(AuthenticationException.class)
	public ResponseEntity<APIReturnObject> AuthenticationException(AuthenticationException e) {
		logger.error(e.getMessage());
		APIReturnObject aPIReturnObject = new APIReturnObject();
		aPIReturnObject.setMessage(TokenEnum.TOKEN_AUTH_FAIL.getMessage());
		return new ResponseEntity<APIReturnObject>                                                       (aPIReturnObject,TokenEnum.TOKEN_AUTH_FAIL.getHttpstatus()); 
	}
}

TokenEnum-儲存回傳訊息和狀態碼



package com.stockAPI.enumsave;

import org.springframework.http.HttpStatus;

public enum TokenEnum {
	
	Token_SUCCESS(200,"tokem資訊取得成功",HttpStatus.OK),
	
	TOKEN_ERROR_EXPIRED(1000,"token驗證過期",HttpStatus.REQUEST_TIMEOUT),//httpstatus 408
	TOKEN_AUTH_FAIL(1001,"身分驗證發生錯誤",HttpStatus.FORBIDDEN);//httpstatus 403
	
	private  Integer code;
	private String message;
	private HttpStatus httpstatus;
	
	private TokenEnum( Integer code, String message,HttpStatus httpstatus) {
		this.code = code;
		this.message = message;
		this.httpstatus =httpstatus;
	}

	public Integer getCode() {
		return code;
	}

	public String getMessage() {
		return message;
	}
	
	public HttpStatus getHttpstatus() {
		return httpstatus;
	}

}

在傳送一次post請求就可以發現回傳的格式和狀態碼已經改變

https://ithelp.ithome.com.tw/upload/images/20211024/20138857Brv9duaWDc.png


想了解更多的例外處理和filter可以推薦看這兩篇

Day 17 - Spring Boot 例外處理

Day 21 - Spring Boot & Filter

參考資料

How to manage exceptions thrown in filters in Spring?


上一篇
Angular Stock Route Guards (Day31)
系列文
Angular+Spring Boot API 處理股市資料32

尚未有邦友留言

立即登入留言