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.zuul
zuul-test
pom
1.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-SNAPSHOT

4.0.0

zuul-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 @EnableZuulProxy public class ZuulServerApplication {     public static void main(String[] args) {         SpringApplication.run(ZuulServerApplication.class, args);     } }
  • zuul-service/application.yml

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


    zuul-test
    com.calvin.zuul
    1.0-SNAPSHOT

4.0.0
user-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-service
server:
  port: 8020
eureka:
  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 @EnableFeignClients public 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  */ @RestController public 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 SpringCloud中如何使用Zuul路由网关

从调用结果中可以看到我们从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  */ @Component public 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 SpringCloud中如何使用Zuul路由网关
结果当然是我们定义的熔断器中返回的内容了!

如果需要对其他服务使用同一个熔断器,只需要在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  */ @Component public 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路由网关的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注创新互联行业资讯频道,感谢各位的阅读!


当前名称:SpringCloud中如何使用Zuul路由网关
文章路径:http://ybzwz.com/article/ihhoee.html