服务网关

API网关统一服务入口,可方便实现对平台众多服务接口进行管控,对访问服务的身份认证、防报文重放与防数据篡改、功能调用的业务鉴权、响应数据的脱敏、流量与并发控制,甚至基于API调用的计量或者计费等等

网关分类

  • 开放api
  • 服务网关

接口设计

接口权限(开放接口|内部接口)、考虑幂等性、安全性(Https )防止篡改数据(验证签名)、使用网关拦截 接口实现黑名单和白名单、接口使用http协议+json格式restful 目的为了跨平台。 考虑高并发对接口服务实现保护服务降级、熔断、隔离之类,最后使用统一API管理平台api swagger

应用场景

  • 黑白名单
  • 日志
  • 协议适配
  • 身份认证
  • 计流限流
  • 路由

网关部署架构

202002221510

  • nginx面向服务器
  • 网关面向服务

Spring Cloud Zuul

202037144831

zuul与nginx

  • Nginx是采用服务器负载均衡进行转发
  • Zuul依赖Ribbon和eureka实现本地负载均衡转发

Nginx功能比Zuul功能更加强大,能够整合其他语言比如lua脚本实现强大的功能,同时Nginx可以更好的抗高并发,Zuul网关适用于请求过滤和拦截

使用

  • 添加依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
  • 配置
server.port=8010
spring.application.name=gateway

# 这里的配置表示,访问/bd/** 直接重定向到http://baidu.com/**
zuul.routes.baidu.path=/bd/**
zuul.routes.baidu.url=http://baidu.com/

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/
@EnableZuulProxy

默认路由规则

http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**

比如访问 http://localhost:8010/producer/

则gateway就会把请求转发到producer服务上面去

简化路由配置

zuul:
  routes:
    user-service: /user-service/** # 这里是映射路径

Zuul的核心

  • Fliter

  • 场景
    • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
    • 异常处理:一般会在error类型和post类型过滤器中结合来处理。
    • 服务调用时长统计

自定义Filter

  • 实现ZuulFilter
@Component
public class MyFilter extends ZuulFilter {

    @Override
    public String filterType() {return FilterConstants.PRE_TYPE;}

    @Override
    public int filterOrder() {return FilterConstants.PRE_DECORATION_FILTER_ORDER;}

    @Override
    public boolean shouldFilter() {return true;}

    @Override
    public Object run() throws ZuulException {

        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        String token = request.getParameter("token");
        if ("my".equals(token)){
            ctx.setSendZuulResponse(true);
            ctx.setResponseStatusCode(200);
            ctx.set("isSuccess",true);
        }else{
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(400);
            ctx.setResponseBody("error token");
            ctx.set("isSuccess",false);

        }
        return null;
    }
}

这样当通过网关访问服务时,不符合条件的请求将会被过滤掉

整合配置中心

  • 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  • 手动配置zuul配置对象
@RefreshScope
@ConfigurationProperties("zuul")
public ZuulProperties zuulProperties() {
    return new ZuulProperties();
}

进行跨域配置

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        final CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true); // 允许cookies跨域
        config.addAllowedOrigin("*");// #允许向该服务器提交请求的URI,*表示全部允许,在SpringMVC中,如果设成*,会自动转成当前请求头中的Origin
        config.addAllowedHeader("*");// #允许访问的头信息,*表示全部
        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
        config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许
        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }
}

忽略

# 忽略该服务
zuul.ignored-services: upload-servie

路由熔断

  • 自定义fallback
@Component
public class MyFallback implements FallbackProvider {
    @Override
    public String getRoute() {
        return "producer";
    }

    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {

        cause.printStackTrace();


        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.valueOf(500);
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return 500;
            }

            @Override
            public String getStatusText() throws IOException {
                return "SERVER ERROR";
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("service is unavailable".getBytes());
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                headers.setContentType(MediaType.TEXT_PLAIN);
                return headers;
            }
        };
    }
}

当producer挂掉时,将会返回相关信息

路由重试

  • 添加依赖
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
  • 配置
#是否开启重试功能
zuul.retryable=true
#对当前服务的重试次数
ribbon.MaxAutoRetries=2
#切换相同Server的次数
ribbon.MaxAutoRetriesNextServer=0

当相同的服务挂掉一部分后,如果多次请求不成功,则接下来的请求则会转发到其他服务上

也就是说,自动的寻找到正确响应的服务上去.错误的实例被抛弃

zuul高可用

  • 启动两个网关实例8000和7000
  • 配置nginx负载均衡
upstream gateway {
        server 127.0.0.1:8000;
        server 127.0.0.1:7000;
}
server {
        listen 6060;
        location / {
                proxy_pass http://gateway;
                proxy_connect_timeout 1s;
                proxy_send_timeout 1s;
                proxy_read_timeout 1s;
        }
}

Spring Cloud Gateway

  • 路由
  • 断言
  • 过滤器

批注 2020-04-07 130836

vs zuul

ZuuL网关属于Netflix公司开源框架,属于第一代微服务网关. GateWay属于SpringCloud自己研发的网关框架,属于第二代微服务网关.

gateway不依赖servlet api,所以性能更强 gateway的转发是在tcp层

配置

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

定义路由规则

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
            .route("path_route", r -> r.path("/hi")
                    .uri("http://localhost:8503"))
            .build();
}
  • 通过时间匹配
builder.routes()
       .route("path_route", r -> r.before(ZonedDateTime.now())
               .uri("http://localhost:8503"))
       .build();
  • 通过Cookie匹配
builder.routes()
       .route("path_route", r -> r.cookie("key","value")
               .uri("http://localhost:8503"))
       .build();
  • 通过header属性匹配
  • 通过Host匹配
  • 通过请求方式匹配
  • 通过请求路径匹配
  • 通过请求参数匹配
  • 通过请求IP匹配

服务化

  • 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
  • 配置
server:
  port: 8888
spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug
  • 默认转发规则

http://网关/服务serviceId/具体的url

Filter

  • PRE

这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等

  • POST

这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等

简单过滤器实例

  • 配置
server:
  port: 8888
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: add_request_parameter_route
        uri: http://localhost:9003
        filters:
        - AddRequestParameter=name, my
        predicates:
          - Method=GET
      discovery:
        locator:
          enabled: true

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8001/eureka/
logging:
  level:
    org.springframework.cloud.gateway: debug

在上面的配置中,添加了一个路由过滤规则:对9003端口的get请求添加一个请求参数name:my

  • 服务化配置

改成 uri: lb://producer 则路由配置只会对producer服务生效

修改路径的过滤器

  • StripPrefix Filter
- id: nameRoot
  uri: lb://producer
  predicates:
    - Path=/name/**
  filters:
    - StripPrefix=2

如果访问/name/my/hello,网关就会将路径修改为/hello

  • PrefixPath Filter
- id: prefixpath_route
  uri: lb://producer
  predicates:
  - Path=*
  filters:
  - PrefixPath=/mypath

自动给URL加上mypath前缀

自定义Filter

@Component
public class TokenFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        var token = exchange.getRequest().getQueryParams().get("token");
        if (!CollectionUtils.isEmpty(token)){
            return chain.filter(exchange);
        }
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.FORBIDDEN);
        return response.writeWith(
                Mono.just(
                        response.bufferFactory().wrap("token is null".getBytes())
                )
        );
    }
}

限速路由器

熔断路由器

  • 依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- id: hystrix_route
  uri: http://localhost:9001
  predicates:
    - Path=/*
  filters:
    - Hystrix=myCommandName

重试路由器

results matching " "

No results matching " "

results matching " "

No results matching " "