zuul 网关过滤器 zuulFilter

文章介绍了ZuulFilter的四个核心方法:filterType、filterOrder、shouldFilter和run,以及它们在Zuul生命周期中的作用。过滤器分为pre、route、post和error四种类型,分别在请求的不同阶段执行。示例代码展示了如何创建一个校验token的pre过滤器和处理异常的error过滤器,用于统一网关的错误响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、zuulFilter 四个方法

继承zuulFilter需要实现四个方法,filterType、filterOrder、shouldFilter、run

  • filterType():过滤器执行类型。有以下四种类型pre、route、post、error
  • filterOrder():过滤器执行顺序,数字越大,优先级越低
  • shouldFilter():是否执行该过滤器,此处为true,则会执行run方法
  • run():过滤器具体执行逻辑

2、过滤器类型 filterType

  • pre:请求被路由到源服务器之前执行的过滤器

    身份认证
    选路由
    请求日志

  • route:处理将请求发送到源服务器的过滤器

  • post:响应从源服务器返回时执行的过滤器

    对响应增加 HTTP 头
    收集统计和度量指标
    将响应以流的方式发送回客户端

  • error:上述阶段中出现错误时执行的过滤器

3、过滤器实例

Spring Cloud Netflix Zuul 中实现过滤器必须包含 4 个基本特征:过滤器类型,执
行顺序,执行条件,动作(具体操作)。这些步骤都是 ZuulFilter 接口中定义的
4 个抽象方法:

package com.xxxx.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
 * 网关过滤器:校验token
*/
@Component
public class CustomFilter extends ZuulFilter {
private static final Logger logger =
LoggerFactory.getLogger(CustomFilter.class);
	/**
	* 过滤器类型
	* pre
	* routing
	* post
	* error
	*
	* @return
	*/
	@Override
	public String filterType() {
		return "pre";
	}
	/**
	* 执行顺序
	* 数值越小,优先级越高
	*
	* @return
	*/
	@Override
	public int filterOrder() {
		return 0;
	}
	/**
	* 执行条件
	* true 开启
	* false 关闭
	*
	* @return
	*/
	@Override
	public boolean shouldFilter() {
		return true;
	}
	/**
	* 动作(具体操作)
	* 具体逻辑
	*
	* @return
	* @throws ZuulException
	*/
	@Override
	public Object run() throws ZuulException {
		RequestContext rc = RequestContext.getCurrentContext();
		HttpServletRequest request = rc.getRequest();
		// 获取表单中的 token
		String token = request.getParameter("token");
		// 业务逻辑处理
		if (null == token) {
		logger.warn("token is null...");
		// 请求结束,不在继续向下请求。
		rc.setSendZuulResponse(false);
		// 响应状态码,HTTP 401 错误代表用户没有访问权限
		rc.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
		// 响应类型
		rc.getResponse().setContentType("application/json;
		charset=utf-8");
		PrintWriter writer = null;
		try {
			writer = rc.getResponse().getWriter();
			// 响应内容
			writer.print("{\"message\":\"" +
			HttpStatus.UNAUTHORIZED.getReasonPhrase() + "\"}");
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (null != writer)
			writer.close();
		}
		} else {
			// 使用 token 进行身份验证
			logger.info("token is OK!");
		}
		return null;
	}
}

4、Zuul生命周期

在这里插入图片描述

5、网关过滤器异常统一处理

  • 禁用 Zuul 默认异常
zuul:
	# 禁用 Zuul 默认的异常处理 filter
	SendErrorFilter:
		error:
			disable: true
  • 实现自定义异常
package com.xxxx.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 异常过滤器
*/
@Component
public class ErrorFilter extends ZuulFilter {
	private static final Logger logger =
	LoggerFactory.getLogger(ErrorFilter.class);
	@Override
	public String filterType() {
		return "error";
	}
	@Override
	public int filterOrder() {
		return 0;
	}
	@Override
	public boolean shouldFilter() {
		return true;
	}
	@Override
	public Object run() throws ZuulException {
		RequestContext rc = RequestContext.getCurrentContext();
		Throwable throwable = rc.getThrowable();
		logger.error("ErrorFilter..." +
		throwable.getCause().getMessage(), throwable);
		// 响应状态码,HTTP 500 服务器错误
		rc.setResponseStatusCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
		// 响应类型
		rc.getResponse().setContentType("application/json;
		charset=utf-8");
		PrintWriter writer = null;
		try {
		writer = rc.getResponse().getWriter();
		// 响应内容
		writer.print("{\"message\":\"" +
		HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase() + "\"}");
		} catch (IOException e) {
		e.printStackTrace();
		} finally {
		if (null != writer)
		writer.close();
		}
		return null;
	}
}
在 Spring 微服务中,可以使用 Zuul 网关实现基于过滤器的限流。Zuul 是 Netflix 开源的一个基于 JVM 的路由和服务端负载均衡器,可以用来构建微服务架构中的网关。 以下是使用 Zuul 实现基于过滤器的限流的步骤: 1. 添加 Zuul 依赖。可以在 Spring Boot 项目中添加以下依赖: ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> ``` 2. 创建一个 Zuul 过滤器。可以实现 com.netflix.zuul.ZuulFilter 接口,并重写其抽象方法。在该过滤器中,可以实现限流逻辑。 3. 将过滤器注册到 Zuul 中。可以在 Spring Boot 应用的配置文件中添加以下配置: ``` zuul: routes: my-service: path: /my-service/** serviceId: my-service filters: rate-limit: type: pre url: http://localhost:8080/limit ``` 其中,my-service 是需要进行限流的服务名,/my-service/** 是需要进行限流的路径,my-service 是该服务的注册名,rate-limit 是自定义的限流过滤器名。 4. 配置限流参数。可以在应用的配置文件中添加以下配置: ``` rate-limiter: enabled: true limit: 1000 time-interval: 1 ``` 其中,enabled 表示是否启用限流,limit 表示每个时间间隔内允许的请求数,time-interval 表示时间间隔。 5. 编写限流逻辑。在自定义的限流过滤器中,可以使用 Redis、Guava、Bucket4j 等工具实现限流逻辑。以下是一个使用 Redis 实现限流的示例: ```java @Component public class RateLimitFilter extends ZuulFilter { private RedisTemplate<String, String> redisTemplate; @Autowired public RateLimitFilter(RedisTemplate<String, String> redisTemplate) { this.redisTemplate = redisTemplate; } @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { String ipAddress = RequestContext.getCurrentContext().getRequest().getRemoteAddr(); String key = "rate-limit:" + ipAddress; ValueOperations<String, String> ops = redisTemplate.opsForValue(); Long count = ops.increment(key, 1); if (count == 1) { redisTemplate.expire(key, 1, TimeUnit.SECONDS); } Long limit = Long.valueOf(redisTemplate.opsForValue().get("rate-limiter:limit")); Long timeInterval = Long.valueOf(redisTemplate.opsForValue().get("rate-limiter:time-interval")); if (count > limit) { throw new RuntimeException("Rate limit exceeded"); } return null; } } ``` 在上面的示例中,我们使用 Redis 存储每个 IP 地址的请求数,并在达到限流阈值时抛出异常。同时,我们从 Redis 中获取限流参数,即每个时间间隔内允许的请求数和时间间隔。 以上就是使用 Zuul 实现基于过滤器的限流的步骤。通过配置和编写逻辑,我们可以在微服务架构中对单个服务或多个服务进行限流。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值