zuul整合ratelimit实现限流
正常调用结果
触发限流后提示
父类pom
<?xml version="1.0" encoding="UTF-8"?>4.0.0 org.example zuul-aprent pom 1.0-SNAPSHOT eureka-service prodoct-service order-service zuul-service zuul-one zuul-two org.springframework.boot spring-boot-starter-parent 2.2.5.RELEASE org.springframework.cloud spring-cloud-dependencies Hoxton.SR3 pom import com.alibaba.cloud spring-cloud-alibaba-dependencies 2.1.0.RELEASE pom import org.apache.maven.plugins maven-compiler-plugin 1.8 1.8 utf-8 org.springframework.boot spring-boot-maven-plugin
zuul网关配置
<?xml version="1.0" encoding="UTF-8"?>zuul-aprent org.example 1.0-SNAPSHOT 4.0.0 com.zuul zuul-two org.springframework.cloud spring-cloud-starter-netflix-zuul org.projectlombok lombok 1.18.16 org.springframework.cloud spring-cloud-starter-netflix-eureka-client com.marcosbarbero.cloud spring-cloud-zuul-ratelimit 2.2.5.RELEASE org.springframework.boot spring-boot-starter-data-redis com.google.code.gson gson 2.8.6 org.springframework.boot spring-boot-maven-plugin zuul
server.port=1004 spring.application.name=zuul-two #注册到eureka注册中心,如果是注册到集群就用逗号连接多个,单实例写上一个就好 eureka.client.service-url.defaultZone=http://localhost:8761/eureka logging.level.com.zuul=debug logging.level.web=debug spring.devtools.add-properties=false #开启限流保护 zuul.ratelimit.enabled=true #限流数据存储方式 zuul.ratelimit.repository=redis #自定义需要被限流的服务名 zuul.ratelimit.policy-list.order-service[0].limit=5 zuul.ratelimit.policy-list.order-service[0].refresh-interval=60 spring.redis.database=1 spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=
package com.zuul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * @author yourheart * @Description 自定义限流策略 * @create 2022-05-21 23:44 */ @SpringBootApplication //开启zuul注解 @EnableZuulProxy @EnableDiscoveryClient public class ZuulTwoApplication { public static void main(String[] args) { SpringApplication.run(ZuulTwoApplication.class,args); } }
配置token验证
package com.zuul.config; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.io.PrintWriter; /** * @author yourheart * @Description * @create 2022-05-09 21:56 */ @Component @Slf4j public class AccessFilter extends ZuulFilter { @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { //获取请求上下文 RequestContext rc = RequestContext.getCurrentContext(); HttpServletRequest request = rc.getRequest(); String token=request.getHeader("token"); if (null==token){ log.warn("【token为空】"); //请求结束 rc.setSendZuulResponse(false); //状态码,401未授权 rc.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); rc.getResponse().setContentType("application/jsop; charset=utf-8"); PrintWriter writer=null; try { writer=rc.getResponse().getWriter(); writer.print("401,登录未授权"); } catch (IOException e) { e.printStackTrace(); } }else { log.info("【token id ok】token:{}",token); } return null; } }
自定义限流策略
package com.zuul.config; import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitUtils; import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties; import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.DefaultRateLimitKeyGenerator; import org.springframework.cloud.netflix.zuul.filters.Route; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * @author yourheart * @Description * @create 2022-05-21 23:46 */ @Component public class RateLimitKeyGenerator extends DefaultRateLimitKeyGenerator { public RateLimitKeyGenerator(RateLimitProperties properties, RateLimitUtils rateLimitUtils) { super(properties, rateLimitUtils); } /** * 自定义限流策略 * @param request * @param route * @param policy * @return */ @Override public String key(HttpServletRequest request, Route route, RateLimitProperties.Policy policy) { return super.key(request, route, policy)+":"+request.getParameter("orderId"); } }
定制触发限流返回的错误信息
package com.zuul.handler; import com.google.gson.JsonObject; import org.springframework.boot.web.servlet.error.ErrorController; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author yourheart * @Description * @create 2022-05-22 10:51 */ @RestController public class ExceptionHandler implements ErrorController { @Override public String getErrorPath() { return "error"; } @RequestMapping(value="/error") public String error(){ JsonObject jsonObject=new JsonObject(); jsonObject.addProperty("code","429"); jsonObject.addProperty("msg","已触发限流,服务不可用"); String result = jsonObject.toString(); return result; } }
<?xml version="1.0" encoding="UTF-8"?>package com.order; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author yourheart * @Description * @create 2022-04-20 21:38 */ @SpringBootApplication @EnableDiscoveryClient @EnableFeignClients public class OrderApplication { public static void main(String[] args) { SpringApplication.run(OrderApplication.class,args); } } package com.order; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @author yourheart * @Description * @create 2022-04-20 21:46 */ @RestController @RequestMapping("/order") @Slf4j public class OrderController { @Autowired private ProductService productService; @GetMapping("/getId") public String getId(Integer orderId){ return "返回的订单号:"+orderId; } @GetMapping("/getOrder/{id}") public String getProduct(@PathVariable String id){ log.info("【调用消费者入参】:{}",id); String selectProduct = productService.selectProduct(id); return selectProduct; } } package com.order; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient(value = "product-service") public interface ProductService { @GetMapping("/product/getProduct/{id}") String selectProduct(@PathVariable String id); } zuul-aprent org.example 1.0-SNAPSHOT 4.0.0 com.order order-service org.springframework.cloud spring-cloud-starter-netflix-eureka-client org.springframework.cloud spring-cloud-starter-openfeign org.springframework.boot spring-boot-starter-web com.alibaba fastjson 1.2.7 org.projectlombok lombok 1.18.16 org.springframework.boot spring-boot-maven-plugin order
productService.selectProduct(id)该方法可以自己定义
eureka项目
<?xml version="1.0" encoding="UTF-8"?>server.port=8761 spring.application.name=eureka-service eureka.instance.hostname=localhost eureka.client.service-url.defaultZone=http://localhost:8761/eureka eureka.client.register-with-eureka=false eureka.client.fetch-registry=false logging.level.com.eureka=info logging.level.web=info spring.devtools.add-properties=false package com.eureka; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @author yourheart * @Description * @create 2022-04-20 21:17 */ @SpringBootApplication @EnableEurekaServer public class EurekaApplication { public static void main(String[] args) { SpringApplication.run(EurekaApplication.class,args); } } zuul-aprent org.example 1.0-SNAPSHOT 4.0.0 com.eureka eureka-service org.springframework.cloud spring-cloud-starter-netflix-eureka-server org.springframework.boot spring-boot-maven-plugin eureka
调用http://127.0.0.1:1004/order-service/order/getId?orderId=10
本次配置的是60秒内,调用5次触发限流