千家信息网

SpringCloud中如何使用Zuul路由网关

发表于:2025-01-24 作者:千家信息网编辑
千家信息网最后更新 2025年01月24日,SpringCloud中如何使用Zuul路由网关,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、Zuul的作用1. 网关功能网关可以将
千家信息网最后更新 2025年01月24日SpringCloud中如何使用Zuul路由网关

SpringCloud中如何使用Zuul路由网关,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

一、Zuul的作用

1. 网关功能

  • 网关可以将所有的api统一暴露,保护其他服务api接口和信息,以防止被外界直接调用

  • 网关可以做身份认证和权限认证,防止非法请求操作API,保护服务

  • 网关可以实现监控功能,实时日志输出,对请求进行记录

  • 网关可以实现流量监控,便于在高流量情况下对服务进行降级

2. 智能路由

  • Zuul可以和Ribbon、Eureka相结合,实现智能路由和负载均衡

  • 通过一定策略,把请求流量分发到集群状态的多个实例中

  • 可以将API从内部接口中分离出来,方便单测

二、Zuul的工作原理

Zuul基于Servlet实现,通过自定义的ZuulServlet来对请求进行控制,Zuul中有一系列的过滤器,这些过滤器是同样是Zuul的实现关键,请求发起和响应期间,通过这些过滤器实现Zuul的功能。具体有以下四个:

  1. PRE过滤器:在请求路由到具体的服务之前执行,用途:安全验证(身份校验,参数校验、ip黑白名单);

  2. ROUTING过滤器 :在请求的服务到具体的微服务实例时执行,用途:进行网络请求(默认使用HttpClient);

  3. POST过滤器:在请求路由到微服务之后执行,用途:统计信息,回传响应;

  4. ERROR过滤器:在其他过滤器发生错误的时候执行,用途:保证请求能够正确响应;

ZuulFilter中的方法有以下四个,继承ZuulFilter并且重写以下四个方法即可实现一个过滤器。

  1. public String filterType(); 返回该Filter的类型,即如上四种过滤器。

  2. public int filterOrder(); 返回该过滤器的执行顺序。

  3. public boolean shouldFilter(); 返回该过滤器是否需要执行。

  4. public Object run(); 执行具体的过滤逻辑。

ZuulServlet是Zuul的核心Servlet,负责初始化ZuulFilter并且编排这些过滤器,具体代码在service()方法中。

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {        try {            this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);            RequestContext context = RequestContext.getCurrentContext();            context.setZuulEngineRan();            try {                this.preRoute();            } catch (ZuulException var13) {                this.error(var13);                this.postRoute();                return;            }            try {                this.route();            } catch (ZuulException var12) {                this.error(var12);                this.postRoute();                return;            }            try {                this.postRoute();            } catch (ZuulException var11) {                this.error(var11);            }        } catch (Throwable var14) {            this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName()));        } finally {            RequestContext.getCurrentContext().unset();        }    }

RequestContextZuulFilter中负责上下文衔接的角色,其本身是一个ConcurrentHashMap,包含Request和Response、routeType、routeHost等上下文需要的对象。

三、项目实战

(1)项目搭建
  • 父级项目zuul-test/pom.xml

com.calvin.zuulzuul-testpom1.0-SNAPSHOT    eureka-server    user-service    zuul-service    org.springframework.boot    spring-boot-starter-parent    1.5.3.RELEASE    UTF-8    UTF-8    1.8                        org.springframework.cloud            spring-cloud-dependencies            Dalston.SR4            pom            import            
  • zuul-service/pom.xml

    zuul-test    com.calvin.zuul    1.0-SNAPSHOT4.0.0zuul-service                org.springframework.boot        spring-boot-starter-web                    org.springframework.cloud        spring-cloud-starter-eureka                org.springframework.cloud        spring-cloud-starter-zuul                            org.springframework.boot            spring-boot-maven-plugin            
  • zuul-service/ZuulApplication.java

/** * 

* 启动类 *

* @author Calvin * @date 2019/10/25 * @since 1.0 */@SpringBootApplication@EnableEurekaClient@EnableZuulProxypublic class ZuulServerApplication { public static void main(String[] args) { SpringApplication.run(ZuulServerApplication.class, args); }}
  • zuul-service/application.yml

spring:  application:    name: zuul-serviceserver:  port: 8030eureka:  client:    service-url:      defaultZone: http://localhost:8010/eureka/  instance:    hostname: localhostzuul:  routes:    user-api:      path: /user/**      serviceId: user-service
  • user-service/pom.xml

    zuul-test    com.calvin.zuul    1.0-SNAPSHOT4.0.0user-service            org.springframework.cloud        spring-cloud-starter-eureka                org.springframework.cloud        spring-cloud-starter-feign                org.springframework.boot        spring-boot-starter-web                            org.springframework.boot            spring-boot-maven-plugin            
  • user-service/application.yml

spring:  application:    name: user-serviceserver:  port: 8020eureka:  client:    service-url:      defaultZone: http://localhost:8010/eureka/  instance:    hostname: localhost
  • user-service/UserApplication.java

/** * 

* 启动类 *

* @author Calvin * @date 2019/10/25 * @since 1.0 */@SpringBootApplication@EnableEurekaClient@EnableFeignClientspublic class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); }}
  • user-service/controller/UserController.java

/** * 

* * @author Calvin * @date 2019/10/25 * @since */@RestControllerpublic class UserController { /** * 简单构建一个User */ @GetMapping("/userDetail/{userId}") public SysUser getUserDetail(@PathVariable("userId") String userId){ SysUser sysUser = new SysUser(); sysUser.setId(userId); sysUser.setAge(20); sysUser.setPassword(MD5Utils.digestAsHex("123456")); sysUser.setUsername("Calvin"); //图片来自百度 sysUser.setHeadImg("https://b-ssl.duitang.com/uploads/item/201510/17/20151017181645_c5hWE.thumb.700_0.jpeg"); return sysUser; }}
(2)智能路由

依次启动eureka-server, user-server, zuul-server
浏览器调用 http://localhost:8030/user/userDetail/1

从调用结果中可以看到我们从zuul-service中调用了user-service的方法,并且调用成功。从而证明路由配置可用;
如需配置版本号,我们只需要咱zuul-service/application.yml中添加配置:zuul.prefix=v1

(3)故障熔断

如果需要在Zuul中实现服务熔断,只需要实现ZuulFallbackProvider接口,重写其中两个方法,通过getRoute()方法返回我们需要熔断的路由,通过fallbackResponse()方法来重写熔断时执行的逻辑。

如下,我们实现第一个user-service的熔断器

/** * 

* user-service熔断器 *

* * @author Calvin * @date 2019/10/27 * @since */@Componentpublic class UserServiceCallback implements ZuulFallbackProvider { @Override public String getRoute() { return "user-service"; } @Override public ClientHttpResponse fallbackResponse() { return new CommonClientResponse(); }}

贴上CommonClientResponse的代码,就是针对ClientHttpResponse接口的封装

/** * 

封装的通用返回类

* * @author Calvin * @date 2019/10/27 * @since */public class CommonClientResponse implements ClientHttpResponse { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 0; } @Override public String getStatusText() throws IOException { return "success"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("hello , this is zuul fallback".getBytes()); } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; }}

接下来做个测试,我们停掉user-service服务,然后再访问 http://localhost:8030/user/userDetail/1
结果当然是我们定义的熔断器中返回的内容了!

如果需要对其他服务使用同一个熔断器,只需要在getRoute()方法中返回通配符 return "*"就可以了  

网关测试

ZuulFilter是Zuul实现过滤和网关的关键,此类有四个枚举值,分别代表Zuul中的过滤器类型。如果需要实现过滤,只需要继承ZuulFilter,并且指定其过滤器类型,枚举值为:

     /**         * {@link ZuulFilter#filterType()} error type.         */        String ERROR_TYPE = "error";        /**         * {@link ZuulFilter#filterType()} post type.         */        String POST_TYPE = "post";        /**         * {@link ZuulFilter#filterType()} pre type.         */        String PRE_TYPE = "pre";        /**         * {@link ZuulFilter#filterType()} route type.         */        String ROUTE_TYPE = "route";

简单实现一个过滤器

/** * 

header过滤器

* * @author Calvin * @date 2019/10/27 * @since */@Componentpublic class TokenFilter extends ZuulFilter { private static final Logger logger = LoggerFactory.getLogger(TokenFilter.class); @Override public String filterType() { return PRE_TYPE; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); logger.info("request_url : {}, request_headers: {}",request.getRequestURI(), JSON.toJSON(request.getHeaderNames()).toString()); return null; }}

重新启动zuul-service,调用服务控制台已经可以输出如下内容:

2019-11-12 22:04:36.726  INFO 58984 --- [nio-8030-exec-4] com.calvin.zuul.filter.TokenFilter       : request_url : /user/userDetail/1, request_headers: ["host","connection","cache-control","upgrade-insecure-requests","user-agent","sec-fetch-user","accept","sec-fetch-site","sec-fetch-mode","accept-encoding","accept-language","cookie"]

若需要拦截请求,或者设置白名单等,在RequestContext中设置好自己的statusCode等,就可以了

requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(401);ctx.getResponse().getWriter().write("there is no token found,please relogin!")

看完上述内容,你们掌握SpringCloud中如何使用Zuul路由网关的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注行业资讯频道,感谢各位的阅读!

0