SpringCloud微服务 之Zuul(二)

秒速五厘米 2022-04-18 05:49 377阅读 0赞

前言

Zuul的基本使用FallBack+Filter。

  • Zuul Filter
    Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是“PRE”、“ROUTING”、“POST”、“ERROR”,整个生命周期可以用下图来表示:
    在这里插入图片描述
  • Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

    • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
    • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
    • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
    • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
  • Zuul中默认实现的Filter
    在这里插入图片描述
  • 禁用指定的Filter

    1. zuul:
    2. FormBodyWrapperFilter:
    3. pre:
    4. disable: true

案例

  • Eureka Server端编写(参考前例)。
    在这里插入图片描述
  • Eureka Client端服务调用方编写。

    • 项目结构
      在这里插入图片描述
    • CoreCode

      1. <?xml version="1.0" encoding="UTF-8"?>
      2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      4. <modelVersion>4.0.0</modelVersion>
      5. <artifactId>microservice-deal-gateway-zuul-filter</artifactId>
      6. <packaging>jar</packaging>
      7. <name>microservice-deal-gateway-zuul-filter</name>
      8. <description>Demo project for Spring Boot</description>
      9. <parent>
      10. <groupId>com.example</groupId>
      11. <artifactId>microservice-deal-parent</artifactId>
      12. <version>0.0.1-SNAPSHOT</version>
      13. </parent>
      14. <dependencies>
      15. <!-- Zuul -->
      16. <dependency>
      17. <groupId>org.springframework.cloud</groupId>
      18. <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
      19. </dependency>
      20. </dependencies>
      21. </project>
      22. @Component
      23. public class MyFallbackProvider implements FallbackProvider {
      24. @Override
      25. public String getRoute() {
      26. // 表明是为哪个微服务提供回退,*表示为所有微服务提供回退
      27. return "*";
      28. }
      29. @Override
      30. public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
      31. return new ClientHttpResponse() {
      32. @Override
      33. public HttpStatus getStatusCode() throws IOException {
      34. return HttpStatus.OK; // 请求网关成功了,所以是ok
      35. }
      36. @Override
      37. public int getRawStatusCode() throws IOException {
      38. return HttpStatus.OK.value();
      39. }
      40. @Override
      41. public String getStatusText() throws IOException {
      42. return HttpStatus.OK.getReasonPhrase();
      43. }
      44. @Override
      45. public void close() {
      46. }
      47. @Override
      48. public InputStream getBody() throws IOException {
      49. JSONObject json = new JSONObject();
      50. json.put("state", "501");
      51. json.put("msg", "后台接口错误");
      52. return new ByteArrayInputStream(json.toJSONString().getBytes("UTF-8")); // 返回前端的内容
      53. }
      54. @Override
      55. public HttpHeaders getHeaders() {
      56. HttpHeaders httpHeaders = new HttpHeaders();
      57. httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8); // 设置头
      58. return httpHeaders;
      59. }
      60. };
      61. }
      62. }
      63. @Component
      64. public class ErrorFilter extends ZuulFilter {
      65. private static Logger log = LoggerFactory.getLogger(ErrorFilter.class);
      66. @Override
      67. public String filterType() {
      68. // 异常过滤器
      69. return "error";
      70. }
      71. @Override
      72. public int filterOrder() {
      73. // 优先级,数字越大,优先级越低
      74. return 0;
      75. }
      76. @Override
      77. public boolean shouldFilter() {
      78. // 是否执行该过滤器,true代表需要过滤
      79. return true;
      80. }
      81. @Override
      82. public Object run() {
      83. RequestContext ctx = RequestContext.getCurrentContext();
      84. log.info("进入异常过滤器");
      85. System.out.println(ctx.getResponseBody());
      86. ctx.setResponseBody("出现异常");
      87. return null;
      88. }
      89. @Component
      90. public class AccessUserNameFilter extends ZuulFilter {
      91. @Override
      92. public Object run() {
      93. RequestContext ctx = RequestContext.getCurrentContext();
      94. HttpServletRequest request = ctx.getRequest();
      95. System.out.println(String.format("%s AccessUserNameFilter request to %s", request.getMethod(),
      96. request.getRequestURL().toString()));
      97. String username = request.getParameter("username");// 获取请求的参数
      98. if (null != username && username.equals("Dustyone")) {// 如果请求的参数不为空,且值为chhliu时,则通过
      99. ctx.setSendZuulResponse(true);// 对该请求进行路由
      100. ctx.setResponseStatusCode(200);
      101. ctx.set("isSuccess", true);// 设值,让下一个Filter看到上一个Filter的状态
      102. return null;
      103. } else {
      104. ctx.setSendZuulResponse(false);// 过滤该请求,不对其进行路由
      105. ctx.setResponseStatusCode(401);// 返回错误码
      106. ctx.setResponseBody("{\"result\":\"username is not correct!\"}");// 返回错误内容
      107. ctx.set("isSuccess", false);
      108. return null;
      109. }
      110. }
      111. @Override
      112. public boolean shouldFilter() {
      113. return true;// 是否执行该过滤器,此处为true,说明需要过滤
      114. }
      115. @Override
      116. public int filterOrder() {
      117. return 0;// 优先级为0,数字越大,优先级越低
      118. }
      119. @Override
      120. public String filterType() {
      121. return "pre";// 前置过滤器
      122. }
      123. @Component
      124. public class AccessPasswordFilter extends ZuulFilter {
      125. @Override
      126. public Object run() {
      127. RequestContext ctx = RequestContext.getCurrentContext();
      128. HttpServletRequest request = ctx.getRequest();
      129. System.out.println(String.format("%s AccessPasswordFilter request to %s", request.getMethod(),
      130. request.getRequestURL().toString()));
      131. String username = request.getParameter("password");
      132. if (null != username && username.equals("123456")) {
      133. ctx.setSendZuulResponse(true);
      134. ctx.setResponseStatusCode(200);
      135. ctx.set("isSuccess", true);
      136. return null;
      137. } else {
      138. ctx.setSendZuulResponse(false);
      139. ctx.setResponseStatusCode(401);
      140. ctx.setResponseBody("{\"result\":\"password is not correct!\"}");
      141. ctx.set("isSuccess", false);
      142. return null;
      143. }
      144. }
      145. @Override
      146. public boolean shouldFilter() {
      147. RequestContext ctx = RequestContext.getCurrentContext();
      148. return (boolean) ctx.get("isSuccess");// 如果前一个过滤器的结果为true,则说明上一个过滤器成功了,需要进入当前的过滤,如果前一个过滤器的结果为false,则说明上一个过滤器没有成功,则无需进行下面的过滤动作了,直接跳过后面的所有过滤器并返回结果
      149. }
      150. @Override
      151. public int filterOrder() {
      152. return 1; // 优先级设置为1
      153. }
      154. @Override
      155. public String filterType() {
      156. return "pre";
      157. }
      158. public class AccessTokenFilter extends ZuulFilter {
      159. @Override
      160. public Object run() {
      161. RequestContext ctx = RequestContext.getCurrentContext();
      162. HttpServletRequest request = ctx.getRequest();
      163. System.out.println(String.format("%s AccessTokenFilter request to %s", request.getMethod(),
      164. request.getRequestURL().toString()));
      165. ctx.setSendZuulResponse(true);
      166. ctx.setResponseStatusCode(200);
      167. ctx.setResponseBody("{\"name\":\"Dustyone\"}");// 输出最终结果
      168. return null;
      169. }
      170. @Override
      171. public boolean shouldFilter() {
      172. return true;
      173. }
      174. @Override
      175. public int filterOrder() {
      176. return 0;
      177. }
      178. @Override
      179. public String filterType() {
      180. return "post";// 在请求被处理之后,会进入该过滤器
      181. }
      182. @SpringBootApplication
      183. @EnableDiscoveryClient
      184. @EnableZuulProxy
      185. public class MicroserviceDealGatewayZuulFilterApplication {
      186. public static void main(String[] args) {
      187. SpringApplication.run(MicroserviceDealGatewayZuulFilterApplication.class, args);
      188. }
      189. /**
      190. * 该示例是将userservice-v1映射到/v1/uservice/中,常用于版本管理中,如APP端调用的API带有版本信息(服务-版本),
      191. * Zuul为这些不同版本的微服务应用生成以版本代号作为路由前缀定义的路由规则。
      192. * 通过具有版本号前缀的URL路径,可以很容易通过路径表达式来归类和管理这些具有版本信息的微服务
      193. * @return
      194. */
      195. @Bean
      196. public PatternServiceRouteMapper serviceRouteMapper() {
      197. // 调用构造函数PatternServiceRouteMapper(String servicePattern, String
      198. // routePattern)
      199. // servicePattern指定微服务的正则
      200. // routePattern指定路由正则
      201. return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)", "${version}/${name}");
      202. }
      203. server:
      204. port: 8040
      205. spring:
      206. application:
      207. name: microservice-deal-gateway-zuul-fallback
      208. eureka:
      209. client:
      210. service-url:
      211. #defaultZone: http://localhost:8080/eureka/
      212. defaultZone: http://Dustyone:bai5331359@localhost:8080/eureka/
      213. instance:
      214. prefer-ip-address: true
      215. #zuul:routes:deal-route: path: /deal/** service-id: microservice-deal-cloud
      216. # 这样访问Zuul的/deal/1路径,请求将会被转发到microservice-deal-cloud的/deal/1,可查看日志打印,有助于理解。
      217. zuul:
      218. routes:
      219. microservice-deal-cloud:
      220. path: /api-deal/**
      221. strip-prefix: true
      222. #设置feign的hystrix响应超时时间(必须)
      223. hystrix:
      224. command:
      225. default:
      226. execution:
      227. isolation:
      228. thread:
      229. timeoutInMilliseconds: 5000
      230. ribbon:
      231. eureka:
      232. enabled: true # 禁用掉ribbon的eureka使用。详见:http://cloud.spring.io/spring-cloud-static/Camden.SR3/#_example_disable_eureka_use_in_ribbon
      233. NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #Ribbon均衡负载策略
      234. management:
      235. security:
      236. enabled: false
  • Eureka Client端服务提供方编写
  • 访问:http://localhost:8040/api-deal/deal/1
    在这里插入图片描述
  • 访问:http://localhost:8040/api-deal/deal/1?username=Dustyone
    在这里插入图片描述
  • 访问:
    在这里插入图片描述
  • Hystrix熔断机制:

    1. @GetMapping("/deal/{id}")
    2. public Deal findById(@PathVariable Integer id) throws InterruptedException {
    3. Thread.sleep(3000);
    4. Deal deal = new Deal(id, "Dustyone", "Heyt", 22, 18,port);
    5. return deal;
    6. }
  • 重启microservice-deal-cloud服务节点,访问:http://localhost:8040/api-deal/deal/1?username=Dustyone&password=123456:
    在这里插入图片描述

小结

  • 本案小节使用的案例:microservice-deal-eureka-authentication、microservice-deal-cloud、microservice-deal-gateway-zuul-filter。

发表评论

表情:
评论列表 (有 0 条评论,377人围观)

还没有评论,来说两句吧...

相关阅读

    相关 服务SpringCloud zuul网关

    一、存在的问题 在之前的文章中,微服务架构已经初具雏形。但还有一些问题:不同的微服务一般会有不同的网 络地址,客户端在访问这些微服务时必须记住几十甚至几百个地址,这对于客