Hello, Freakin world!

[Zuul] pre 타입 필터 작성하기 - 요청 서비스 ID 부여하기 본문

Spring Cloud/Gateway

[Zuul] pre 타입 필터 작성하기 - 요청 서비스 ID 부여하기

johnna_endure 2021. 3. 13. 16:46

먼저 사전 필터를 구현해보도록 하겠습니다.

 

필터를 구현하는 방법은 간단합니다.

주울에서 제공하는 추상 클래스인 ZuulFilter를 상속하면 됩니다.

 

서비스에 대한 요청 흐름을 추적하기 위해 correlation-id를 모든 요청에 추가하기로 하고 TrackingFilter 클래스를 생성합니다.

 

TrackingFilter

package springboot.cloud.zuulexample.filter;

...
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

/*
게이트웨이로 들어오는 모든 요청에 correlation id를 추가합니다.
 */
@Component
public class TrackingFilter extends ZuulFilter {
    private final String FILTER_TYPE = "pre";
    private final int FILTER_ORDER = 1;
    private final boolean SHOULD_FILTER = true;
    private final Logger logger = LoggerFactory.getLogger(TrackingFilter.class);

    @Override
    public String filterType() {
        return FILTER_TYPE;
    }

    @Override
    public int filterOrder() {
        return FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() {
        return SHOULD_FILTER;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        if(!hasCorrelationId(requestContext)) {
            String correlationId = generateCorrelationId();
            requestContext.addZuulRequestHeader("correlation-id", correlationId);
            logger.info("correlation-id generated in tracking filter: {}.", correlationId);
            return null;
        }
        logger.info("correlation-id already exists : {}.", 
            requestContext.getZuulRequestHeaders().get("correlation-id"));
        return null;
    }

    private boolean hasCorrelationId(RequestContext requestContext) {
        return requestContext.getZuulRequestHeaders().containsKey("correlation-id");
    }

    private String generateCorrelationId() {
        return UUID.randomUUID().toString();
    }

}

ZuulFilter를 상속하면 4가지 메서드를 오버라이드 해야됩니다.

 

String filterType()

필터의 타입을 정의하는 메서드입니다.

 

타입에 따라

    pre => "pre" ,

    post => "post",

    route => "route",

    error => "error",

위와 같이 String을 반환하면 됩니다.


int filterOrder()

각 타입 별로 순서를 정의합니다.

필터 순서에 따라 결과가 달라질 수 있기 때문에 그에 맞게 순서를 정해줘야 합니다.

 

필터는 filterOrder 값에 따라 정렬되며 값이 순차적일 필요는 없습니다. 작은 값이 우선권을 가집니다.

(참고로 Integer.compare()를 이용해 값이 정렬되며, 값이 음수여도 동일하게 동작합니다.)  


boolean shouldFilter()

true를 반환하면 run 메서드를 호출해 기능을 수행합니다.

여기서는 모든 요청를 대상으로 하기 때문에 간단하게 true로 지정했지만, 여러 조건이 추가될 수 있습니다.


Object run() throws ZuulException

필터가 수행할 기능을 이 메서드에 작성합니다.

눈여겨 볼 점은 요청 정보에 접근하기 위해 RequestContext.getCurrentContext()를 이용한 점입니다.

주울은 RequestContext를 통해 각 필터에서 요청 정보에 접근할 수 있도록 합니다.

 

반환값은 그냥 null이나 어떤 객체를 반환해도 상관없습니다.

어차피 추상 ZuulFilter 클래스에서 이 반환값을 사용하지 않기 때문에 여기선 그냥 null을 반환합니다.

 

여기서는 간단하게 correlation-id가 있는지 확인하고 없는 경우 UUID 값을 생성해 추가하도록 했습니다.


이제 호출되는 서비스에서 correlation-id를 바로 확인할 수 있도록 간단한 엔드포인트를 작성합니다.

 

MemberRestController

@RestController
public class MemberRestController {

	...
    
    @GetMapping("/correlation-id")
    public String getCorrelationHeaders(HttpServletRequest request) {
        return request.getHeader("correlation-id");
    }
}

클라이언트가 http://게이트웨이_호스트/api/memberservice/correlation-id 를 호출해

correlation-id가 브라우저에 찍히면 성공!

 

성공!

 

 

Comments