Zuul Service Gateway Filters and Resilience Patterns

Core Zuul Filter Architecture

Filters serve as the fundamental building blocks in Zuul, enabling control over external service interactions. The filter lifecycle comprises four distinct phases: "PRE", "ROUTING", "POST", and "ERROR", as illustrated in the following diagram:

  • PRE: Executes before request routing occurs. Used for authentication, service selection, and debug logging.
  • ROUTING: Handles actual request forwarding to microservices using Apache HttpClient or Netflix Ribbon.
  • POST: Processes responses after microservice invocation. Adds standard HTTP headers, collects metrics, and sends responses to clients.
  • ERROR: Triggered when exceptions occur in other phases.

Default Zuul Filter Implementations

Type Order Filter Purpose
pre -3 ServletDetectionFilter Identifies Servlet type
pre -2 Servlet30WrapperFilter Wraps HttpServletRequest
pre -1 FormBodyWrapperFilter Encapsulates request body
route 1 DebugFilter Sets debug flags
route 5 PreDecorationFilter Prepares request context
route 10 RibbonRoutingFilter Routes by serviceId
route 100 SimpleHostRoutingFilter Routes by URL
route 500 SendForwardFilter Handles forward requests
post 0 SendErrorFilter Processes error responses
post 1000 SendResponseFilter Handles successful responses

Custom Filter Implementation

Create custom filters by extending ZuulFilter and implementing four key methods. Consider a security scenario where requests must contain a valid token parameter:


import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import com.netflix.zuul.context.RequestContext;

@Component
public class SecurityValidationFilter extends ZuulFilter {
    
    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }
    
    @Override
    public int filterOrder() {
        return 5;
    }
    
    @Override
    public boolean shouldFilter() {
        return true;
    }
    
    @Override
    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        
        String accessToken = request.getParameter("accessToken");
        
        if (StringUtils.hasText(accessToken)) {
            context.setSendZuulResponse(true);
            context.setResponseStatusCode(HttpStatus.OK.value());
            context.set("validationSuccess", true);
        } else {
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(HttpStatus.BAD_REQUEST.value());
            context.setResponseBody("Access token required");
            context.set("validationSuccess", false);
        }
        return null;
    }
}

Route Circuit Breaking

Implement graceful degradation when backend services fail by creating fallback providers. The modern approach extends FallbackProvider:


@Component
public class ServiceFallbackHandler implements FallbackProvider {
    
    @Override
    public String getRoute() {
        return "product-service";
    }
    
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() {
                return HttpStatus.SERVICE_UNAVAILABLE;
            }
            
            @Override
            public InputStream getBody() {
                return new ByteArrayInputStream(
                    "Service temporarily unavailable".getBytes()
                );
            }
            
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.APPLICATION_JSON);
                return headers;
            }
        };
    }
}

Request Retry Mechanism

Enable automatic retries for transient failures using Spring Retry integartion:


// Add to application.properties
zuul.retryable=true
ribbon.MaxAutoRetries=2
ribbon.MaxAutoRetriesNextServer=0

Dependency configuration:


<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

Enable retry in main application class:


@SpringBootApplication
@EnableRetry
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

Testing reveals three retry attempts when services become unresponsive, demonstrating the resilience pattern in action.

Tags: SpringCloud Zuul microservices api-gateway circuit-breaker

Posted on Thu, 02 Jul 2026 16:51:18 +0000 by zmola