zuul整合ratelimit實現限流
阿新 • • 發佈:2022-05-23
正常呼叫結果
觸發限流後提示
父類pom
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>zuul-aprent</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>eureka-service</module> <module>prodoct-service</module> <module>order-service</module> <module>zuul-service</module> <module>zuul-one</module> <module>zuul-two</module> </modules> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.5.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Hoxton.SR3</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.1.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <!--編譯外掛--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf-8</encoding> </configuration> </plugin> <!--打包外掛--> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
zuul閘道器配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>zuul-aprent</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.zuul</groupId> <artifactId>zuul-two</artifactId> <dependencies> <!--zuul依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <!--lombok依賴--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> <!--客戶端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>com.marcosbarbero.cloud</groupId> <artifactId>spring-cloud-zuul-ratelimit</artifactId> <version>2.2.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <finalName>zuul</finalName> </build> </project>
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"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>zuul-aprent</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.order</groupId> <artifactId>order-service</artifactId> <dependencies> <!--客戶端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--web依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--新增fastjson依賴--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.7</version> </dependency> <!--lombok依賴--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <finalName>order</finalName> </build> </project> 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); }
productService.selectProduct(id)該方法可以自己定義
eureka專案
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>zuul-aprent</artifactId> <groupId>org.example</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.eureka</groupId> <artifactId>eureka-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <finalName>eureka</finalName> </build> </project> 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); } }
呼叫http://127.0.0.1:1004/order-service/order/getId?orderId=10
本次配置的是60秒內,呼叫5次觸發限流