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

 

posted @ 2019-01-16 15:20  宅山仔  阅读(897)  评论(0编辑  收藏  举报