zuul 이상 처리

7745 단어 SpringCloud
주 얼 에서 이상 을 어떻게 처리 하 는 지 에 대해 인터넷 에 많은 방법 이 있 습 니 다. 본 고 는 그 중의 한 가지 만 이야기 하고 자 합 니 다.
우선, 우 리 는 다음 과 같은 몇 가 지 를 알 아야 한다.
  • zuul 에 이상 을 처리 하 는 기본 필터 가 있 습 니 다. 이름 은 SendErrorFilter 입 니 다. 이 필 터 는 실제 적 으로 이상 처 리 를 '/ error' 라 는 경로 로 전송 하 는 것 입 니 다
  • .
  • 한 가 지 를 연결 합 니 다. springboot 에서 이상 을 처리 하 는 기본 적 인 contrller 가 있 습 니 다. 이름 은 BasicErrorController 입 니 다. '/ error' 라 는 경 로 를 비 추 었 습 니 다. 이 contrller 는 이상 한 처리 에 대해 다음 과 같 습 니 다. 비 rest 방식 에 대해 오류 페이지 를 되 돌려 줍 니 다.rest 방식 에 대해 json 을 되 돌려 줍 니 다.(spring boot 를 해 본 사람 은 어떤 오류 페이지 나 어떤 json 인지 알 것 이다)
  • 앞의 2 시 와 결합 하면 zuul 의 기본 적 인 이상 처 리 는 zuul 이 스스로 처리 하지 않 고 spring boot 에 맡 기 는 것 임 을 알 수 있다.

  • 전제 가 끝 난 후에 우 리 는 본 고의 배경 을 이야기 합 니 다. 업무 의 실제 수요 에 따라 우 리 는 zuul 에서 filter 를 정 의 했 습 니 다. 만약 에 어떤 요청 이 이 filter 의 여과 조건 을 만족 시 키 지 못 하면 클 라 이언 트 에 게 사용자 정의 json 형식의 오류 코드 를 되 돌려 줍 니 다.
    필터 에 설 정 된 조건 이 충족 되 지 않 을 때 사용자 정의 이상 을 던 지 는 것 이 우리 의 사고방식 이다.앞서 소개 한 바 에 따 르 면 이 이상 은 zuul 에 내 장 된 처리 이상 filter SendErrorFilter 에 의 해 포착 되 어 spring boot 에 맡 길 수 있 습 니 다.그러나 springboot 의 기본 반환 결 과 는 우리 가 원 하 는 것 이 아 닙 니 다. 사용자 정의 오류 코드 와 오류 메 시 지 를 포함 한 json 을 되 돌려 주 고 싶 습 니 다.그렇다면 우 리 는 어떻게 이 룰 수 있 을 까?본 논문 의 사 고 는 springboot 의 기본 처리 이상 한 contrller BasicErrorController 를 덮어 쓰 는 것 입 니 다.
    다음은 코드 를 보 겠 습 니 다.
  • 우선 사용자 정의 filter 를 보 세 요. 이 필 터 는 간단 합 니 다. 0 시 에서 20 시 사이 에 시스템 에 접근 할 수 없습니다
  •     @Component
        public class AccessTimeFilter extends ZuulFilter {
    
            /**
            *     
            */
            private static final LocalTime NOW = LocalTime.now();
    
            /**
            *   
            */
            private static final LocalTime ZERO_CLOCK = LocalTime.of(0, 0);
    
            /**
            *    
            */
            private static final LocalTime TWENTY_CLOCK = LocalTime.of(20, 0);
    
            @Override
            public String filterType() {
                return FilterConstants.PRE_TYPE;
            }
    
            @Override
            public int filterOrder() {
                return FilterConstants.PRE_DECORATION_FILTER_ORDER - 5;
            }
    
            @Override
            public boolean shouldFilter() {
                return true;
            }
    
            @Override
            public Object run() throws ZuulException {
                if (NOW.isAfter(ZERO_CLOCK) && NOW.isBefore(TWENTY_CLOCK)) {
                	//      0-20        ,     
                    throw new GatewayException(ApiResponseCode.CODE_INVALID_ACCESS_TIME);
                }
                return null;
            }
    
        }
    
  • 그리고 사용자 정의 이상 GatewayException 을 살 펴 보 세 요. 이 이상 은 우리 의 오류 와 오류 메 시 지 를 포장 합 니 다
  • /**
     *        
     *
     *          {@link ZuulException}
     * 
     *      {@link com.netflix.zuul.FilterProcessor#processZuulFilter(ZuulFilter)}         
     */
    public class GatewayException extends ZuulException {
    
        public GatewayException(ApiResponseCode apiResponseCode) {
            super(apiResponseCode.getMessage(), apiResponseCode.getCode(),
                    apiResponseCode.getMessage());
        }
    
        public GatewayException(int code, String message) {
            super(message, code, message);
        }
    
    }
    
  • 마지막 으로, 우 리 는 spring boot 의 기본 처리 이상 한 controller 를 덮어 씁 니 다. spring bootmore 의 이상 처리 controller 를 어떻게 덮어 쓰 는 지 주의 하 십시오. 인터넷 에는 많은 방법 이 있 습 니 다. 여기 서 우리 가 주목 해 야 할 것 은 이상 처리 논리 입 니 다.
  • @RestController
    public class GatewayErrorController implements ErrorController {
    
        /**
         * zuul     
         * 
         * @param request HTTP  
         * @return API    
         */
        @RequestMapping
        public ApiResponse error(HttpServletRequest request, HttpServletResponse response) {
            Integer code = (Integer) request.getAttribute("javax.servlet.error.status_code");
            Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
    
            String message = "       ";
    
            if (exception instanceof ZuulException) {
                message = exception.getMessage();
            }
    
            response.setStatus(HttpStatus.OK.value());
    
            return new ApiResponse<>(code, message);
        }
    
        @Override
        public String getErrorPath() {
            return "/error";
        }
    
    }
    

    핵심 코드 는 여기까지 입 니 다. 효 과 를 보 겠 습 니 다.
    {
        "code": 912,
        "message": "      ,    "
    }
    

    마지막 으로 코드 에 대해 다음 과 같은 몇 가지 설명 이 필요 합 니 다.
  • 사용자 정의 이상 이 왜 계승 되 어야 하 는 지 ZuulException.최초 로 제 가 쓴 사용자 정의 이상 은 계승 되 지 않 았 습 니 다 ZuulException. 이때 돌아 오 는 오류 코드 가 항상 500 인 것 을 발 견 했 습 니 다. 조 사 를 통 해 원인 을 찾 았 습 니 다. FilterProcessor 에는 다음 몇 줄 의 코드 가 있 습 니 다.이 를 통 해 알 수 있 듯 이 포 획 된 이상 이 ZuulException 의 인 스 턴 스 라면 직접 던 집 니 다.그렇지 않 으 면 포 획 된 이상 포장 을 ZuulException 으로 만들어 다시 던진다.문 제 는 캡 처 된 이상 ZuulException 의 인 스 턴 스 가 아 닐 때 zuul 은 오류 코드 를 500 으로 설정 합 니 다 (아래 코드 참조).그래서 우 리 는 사용자 정의 이상 계승 ZuulException 을 선택 합 니 다.
  •         } catch (Throwable e) {
                if (bDebug) {
                    Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + e.getMessage());
                }
                usageNotifier.notify(filter, ExecutionStatus.FAILED);
                if (e instanceof ZuulException) {
                    throw (ZuulException) e;
                } else {
                    ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);
                    ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
                    throw ex;
                }
            }
    
  • 사용자 정의 컨트롤 러 에서 저 희 는 다음 코드 를 사용 하여 오류 코드 와 이상 정 보 를 얻 었 습 니 다.
  •  Integer code = (Integer) request.getAttribute("javax.servlet.error.status_code");
     Exception exception = (Exception) request.getAttribute("javax.servlet.error.exception");
    

    그럼 왜 이렇게 할 수 있 을까요?SendErrorFilter 에서 어떻게 처 리 했 는 지 보면 알 수 있다.
    request.setAttribute("javax.servlet.error.status_code", exception.getStatusCode());
    
    log.warn("Error during filtering", exception.getThrowable());
    request.setAttribute("javax.servlet.error.exception", exception.getThrowable());
    
  • 왜 사용자 정의 컨트롤 러 에서 response 의 상태 코드 를 200 으로 설정 합 니까?이것 은 사실 zuul 과 관련 이 있 습 니 다. zuul 의 RequestContext 에 이런 코드 가 있 습 니 다.
  •     /**
         * Use this instead of response.setStatusCode()
         *
         * @param nStatusCode
         */
        public void setResponseStatusCode(int nStatusCode) {
            getResponse().setStatus(nStatusCode);
            set("responseStatusCode", nStatusCode);
        }
    

    이 를 통 해 알 수 있 듯 이 HTTP 응답 코드 의 값 을 nStatusCode 의 값 으로 설정 합 니 다. 이상 이 발생 했 을 때 이 nStatusCode 의 값 은 이상 한 상태 코드 (아래 SendErrorFilter 의 코드 참조) 입 니 다.이것 은 분명히 우리 가 원 하 는 것 이 아니다.그래서 간단하게 말하자면, 우 리 는 컨트롤 러 에서 응답 코드 를 200 으로 설정 합 니 다.
    	if (dispatcher != null) {
    		ctx.set(SEND_ERROR_FILTER_RAN, true);
    		if (!ctx.getResponse().isCommitted()) {
    			//  HTTP              
    			ctx.setResponseStatusCode(exception.getStatusCode());
    			dispatcher.forward(request, ctx.getResponse());
    		}
    	}
    
  • 상기 첫 번 째 점 에 대해 더 직접적 으로 증명 할 수 있 는 곳 이 있다.
  • request.setAttribute("javax.servlet.error.status_code", exception.getStatusCode());
    

    위 코드 의 exception.getStatusCode() 기본 값 은 다음 과 같 습 니 다.
        default int getStatusCode() {
        	return HttpStatus.INTERNAL_SERVER_ERROR.value();
    	}
    

    좋은 웹페이지 즐겨찾기