spring-cloud zuul网关
API Gateway 是随着微服务(Microservice)这个概念一起兴起的一种架构模式,它用于解决微服务过于分散,没有一个统一的出入口进行流量管理的问题。
使用 Zuul 实现 API Gateway 的功能
1.路由(Routing 代理转发)
idea中,新建一个module,如下部分截图
新建后,idea会加好相应的依赖,如:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
为了支持eureka,添加依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置文件application.yml:
#项目名 spring: application: name: api-gateway-zuul #端口号 server: port: 7002 zuul: routes: #请求重定向 hello: path: /hello/* url: http://www.ityouknow.com/ #默认情况下,Zuul会代理所有注册到Eureka Server的微服务, #并且Zuul的路由规则如下:http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**会被转发到serviceId对应的微服务 eureka-discovery: /discovery/* discovery: path: /discovery2/* serviceId: eureka-discovery eureka: client: serviceUrl: defaultZone: http://localhost:7000/eureka/ instance: lease-expiration-duration-in-seconds: 2 #服务刷新时间配置,每隔这个时间会主动心跳一次 #默认30s lease-renewal-interval-in-seconds: 1 #将ip注册到eureka server上而不是机器主机名 prefer-ip-address: true #ip-address: 127.0.0.1 #InstanceId默认是${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}, #也就是:主机名:应用名:应用端口 #通过instance-id 自定义ip+端口号 instance-id: ${spring.cloud.client.ipaddress}:${server.port}
启动类添加@EnableZuulProxy,支持网关
@SpringBootApplication @EnableZuulProxy public class ApiGatewayZuulApplication { public static void main(String[] args) { SpringApplication.run(ApiGatewayZuulApplication.class, args); } }
测试:
启动eureka-server、eureka-discovery,api-gateway-zuul服务
1.请求:http://localhost:7002/hello/hello,返回的是http://www.ityouknow.com/的页面信息
说明通过配置:
zuul: routes: #请求重定向 hello: path: /hello/* url: http://www.ityouknow.com/
/hello/*的请求转发到了http://www.ityouknow.com/,并将结果返回。
2.请求http://localhost:7002/discovery/test,返回的是eureka-discover服务接口/test的数据。
说明通过配置:
zuul: routes: eureka-discovery: /discovery/*
/discovery/*的请求,转发给了服务eureka-discovery。
下面配置效果和上面一样,/discovery2/*的请求,转发给了服务eureka-discovery。
zuul: routes: path: /discovery2/* serviceId: eureka-discovery
但是如果后端服务多达十几个的时候,每一个都这样配置也挺麻烦的,spring cloud zuul已经帮我们做了默认配置。默认情况下,Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路由规则如下:http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**
会被转发到serviceId对应的微服务。
我们把上面的配置注释调:
请求http://localhost:7002/eureka-discovery/test,同样转发给了服务eureka-discovery。
2.过滤 ( Filtering )
Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是前置(Pre)、后置(Post)、路由(Route)和错误(Error),整个生命周期可以用下图来表示。
一个请求会先按顺序通过所有的前置过滤器,之后在路由过滤器中转发给后端应用,得到响应后又会通过所有的后置过滤器,最后响应给客户端。在整个流程中如果发生了异常则会跳转到错误过滤器中。
Zuul中默认实现的Filter
类型 | 顺序 | 过滤器 | 功能 |
---|---|---|---|
pre | -3 | ServletDetectionFilter | 标记处理Servlet的类型 |
pre | -2 | Servlet30WrapperFilter | 包装HttpServletRequest请求 |
pre | -1 | FormBodyWrapperFilter | 包装请求体 |
route | 1 | DebugFilter | 标记调试标志 |
route | 5 | PreDecorationFilter | 处理请求上下文供后续使用 |
route | 10 | RibbonRoutingFilter | serviceId请求转发 |
route | 100 | SimpleHostRoutingFilter | url请求转发 |
route | 500 | SendForwardFilter | forward请求转发 |
post | 0 | SendErrorFilter | 处理有错误的请求响应 |
post | 1000 | SendResponseFilter | 处理正常的请求响应 |
自定义Filter
实现自定义Filter,需要继承ZuulFilter的类,并覆盖其中的4个方法。
示列
package com.example.apigatewayzuul; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * Created by gexiaoshan on 2019/1/16. */ @Component public class MyFilter extends ZuulFilter { private final Logger logger = LoggerFactory.getLogger(MyFilter.class); @Override public String filterType() { return "pre"; //定义filter的类型,有pre、route、post、error四种 } @Override public int filterOrder() { return 0;// filter执行顺序,通过数字指定 ,优先级为0,数字越大,优先级越低 } @Override public boolean shouldFilter() { return true;// 是否执行该过滤器,此处为true,说明需要过滤 } @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); logger.info("--->>> TokenFilter {},{}", request.getMethod(), request.getRequestURL().toString()); String token = request.getParameter("token");// 获取请求的参数 if (StringUtils.isNotBlank(token)) { ctx.setSendZuulResponse(true); //对请求进行路由 ctx.setResponseStatusCode(200); ctx.set("isSuccess", true); return null; } else { ctx.setSendZuulResponse(false); //不对其进行路由 ctx.setResponseStatusCode(400); ctx.setResponseBody("token is empty"); ctx.set("isSuccess", false); return null; } } }
该filter的作用是判断所有请求是否带有参数token,如果没有直接返回400不路由到后面的服务,如果有token则往后走。
gitHub地址: https://github.com/gexiaoshan518/spring-cloud.git