SpringCloud Alibaba-4-网关


1. 什么是API网关

API网关:是一个服务器,是系统的唯一入口。同时也可以实现服务的路由、负载均衡、鉴权、限流、熔断等功能。

API网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

客户端请求多个微服务,各个服务ip不一样,增加客户端复杂度。
存在跨域,在一定场景下处理相对复杂。
认证复杂,每个服务都需要独立认证。
与微服务耦合太强,微服务变更,客户端需要变更



2. 使用API网关的好处

所有的外部请求都会先经过API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性。

  • 易于监控
  • 统一认证
  • 减少客户端与微服务交互,解耦接口依赖




3. 常用网关

Nginx+lua

Zuul                              Zuul是一种提供动态路由、监视、弹性、安全性等功能的边缘服务。Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器。

SpringCoud Gateway                Spring Cloud GateWay是Spring Cloud的⼀个全新项⽬【SpringCloud公司开发的】,⽬标是取代Netflix Zuul。





3. gateWay入门使用

3.-1 基本概念

  • 断言:用于进行条件判断,只有断言都返回真,才会真正的执行路由。

  • 路由:路由是构建网关的基本模块,它由ID,目标URI,断言Predicates集合,过滤器Filters集合组成,如果断言为true,则匹配该路由。

  • 过滤器:可以在请求被路由前后修改请求和响应的内容。基于过滤器可以实现:安全,监控,限流等问题。

3.0 创建一个服务

ip配置为80端口,当访问这个服务,就是访问我们的getWay。

# 服务端口
server.port=80
# 服务名
spring.application.name=service-gateway

3.1 请求转发的实现

导入依赖

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

添加配置文件

spring:
  application:
    name: springcloud-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  # 当有了注册中心时,网关也是一个服务,所以需要注册到注册中心去。

    gateway:
      discovery:
        locator:
          enabled: true     # 让gateway从nacos中获取服务信息        

      routes:               # routes 是路由,一个GateWay可以包含多个route
        - id: to-user                       # 路由的id,必须唯一。用于区别其他Route。
          uri: lb://springcloud-consumer    # 路由指向的目的地 uri。     lb 动态路由,因为有了注册中心,uri就不是是写,而是写它的服务实例名,lb代表负载均衡。
          order: 1                          # 路由的优先级,数字越小代表路由的优先级越高。
          predicates:                       # predicates  是断言,一个ateWay可以包含多个predicate
            - Path=/user/**                 # 断言规则,用于进行条件判断,只有断言都返回真,才会真正的执行路由。
          #filters:                         # 过滤器,用于在请求的传递过程中,对请求和响应做一些手脚



路由介绍:
Route:主要由 路由id、目标uri、断言集合和过滤器集合组成。

  1. 路由标识,要求唯一,名称任意(默认值 uuid,一般不用,需要自定义)
  2. uri:请求最终被转发到的目标地址
  3. order: 路由优先级,数字越小,优先级越高
  4. predicates:断言数组,即判断条件,如果返回值是boolean,则转发请求到 uri 属性指定的服务中
  5. filters:过滤器数组,在请求传递过程中,对请求做一些修改



断言介绍:

Spring Cloud Gateway包括许多内置的路由断言工厂。所有这些断言都与HTTP请求的不同属性匹配。您可以将多个路由断言工厂与逻辑 and 语句结合使用。

Spring Cloud Gateway 中的断言命名都是有规范的,格式:“xxx + RoutePredicateFactory”,比如权重断言 WeightRoutePredicateFactory,那么配置时直接取前面的 “Weight”。

也可以自定义断言工厂,用到的时候百度吧。




过滤器介绍:

过滤器按区域划分,可分为全局,局部两种过滤器。

  • 局部GatewayFilter:会应用到单个路由上
  • 全局GlobalFilter:会应用到所有路由上

过滤器按作用点划分,可分为Pre(前置),Post(后置)两种过滤器。

  • Pre:在请求转发到后端微服务之前执行。
  • Post:在请求执行完成之后执行。

Spring Cloud Gateway 中的过滤器命名都是有规范的,格式: "xxx + “GatewayFilterFactory”,比如PrefixPathGatewayFilterFactory,那么配置时直接取前面的 “PrefixPath”。




在Spring Cloud Gateway中内置了很多局部Filter。



3.2 介绍用得比较多的内置局部过滤器——Path路径过滤器


Path相关过滤器可以实现URL重写,通过重写URL可以实现隐藏真实路径提高安全性。

Path相关过滤器采用路径正则表达式参数和替换参数,使用Java正则表达式来灵活地重写请求路径。


Gateway过滤器-自定义局部过滤器
自定义(局部)网关过滤器:https://www.bilibili.com/video/BV1R7411774f?p=42&spm_id_from=pageDriver
因为Gateway提供了很多Gateway内置网关(局部)过滤器,所以一般很少使用Gateway自定义网关过滤器。




在Spring Cloud Gateway中内置了很多全局Filter。

全局:会应用到所有的路由上。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能。

多个 GlobalFilter 可以通过 @Order 或者 getOrder() 方法指定执行顺序,order值越小,执行的优先级越高。

Gateway过滤器-自定义全局过滤器:

常见需求:用户需要登录了才放行。

    1. 当客户端第一次请求服务时,服务端对用户进行信息认证(登录)
    2. 认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证
    3. 以后每次请求,客户端都携带认证的token
    4. 服务端对token进行解密,判断是否有效
// 自定义类实现 GlobalFilter , Ordered 接口,加上@Component注解即可;
@Component
public class MyCustomerGlobalFilter implements GlobalFilter ,Ordered {

  // 参数1:是一个响应交互的契约。提供对HTTP请求和响应的访问,并公开额外的服务器端处理相关属性和特性,如请求属性。
  // 参数2:用于承载请求相关的属性和请求体,Spring Cloud Gateway中底层使用Netty处理网络请求。
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
      ServerHttpRequest request = exchange.getRequest();
      ServerHttpResponse response = exchange.getResponse();

      // 判断token,并验证账号密码
      String token = request.getQueryParams().getFirst("token"); // 获取请求对象中参数名为 token 的值,获取第一个参数的值。
      if (StringUtils.isBlank(token)) {

          System.out.println("鉴权失败");
          exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);

          return response.setComplete();
      }

      if(token.equale("abc")){
          // 放行
          return chain.filter(exchange);
      }
  }

  // 该方法用于声明该过滤器执行的优先级
  @Override
  public int getOrder() {   // 返回值越低,表示过滤器执行的优先级越高。
    return 0;
  }
}



4. 跨域问题的解决

方法一:配置类方式

@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }
}

方法二:配置文件方式

spring:
  cloud:
    gateway:
      globalcors: # 全局的跨域处理
        add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
        corsConfigurations:
          '[/**]':
            allowedOrigins: # 允许哪些网站的跨域请求   # 需要 注意的是在springboot2.4之前的版本是使用allowed-origins: "*",在springboot2.4之后的版本是 allowed-origin-patterns: "*"。
              - "http://localhost:8090"
              - "http://www.leyou.com"
            allowedMethods: # 允许的跨域ajax的请求方式
              - "GET"
              - "POST"
              - "DELETE"
              - "PUT"
              - "OPTIONS"
            allowedHeaders: "*" # 允许在请求中携带的头信息
            allowCredentials: true # 是否允许携带cookie
            maxAge: 360000 # 这次跨域检测的有效期



5. Nacos+Spring Cloud Gateway动态路由配置

将网关的一系列配置写到项目的配置文件中,一旦路由策略发生改变必须要重启项目,这样维护成本很高,特别是服务网关作为系统的中心点,一旦重启出现问题,影响面将是十分巨大的。

因此,我们将网关的配置存放到配置中心中,这样由配置中心统一管理,一旦路由发生改变,只需要在配置中心修改即可,降低风险且实时失效。

https://www.cnblogs.com/jian0110/p/12862569.html




6. 自定义全局异常处理器

来源:https://blog.csdn.net/a745233700/article/details/122917167
一旦路由的微服务下线或者失联了,Spring Cloud Gateway直接返回了一个错误页面,如下图:

显然这种异常信息不友好,前后端分离架构中必须定制返回的异常信息。传统的Spring Boot 服务中都是使用 @ControllerAdvice 来包装全局异常处理的,但是由于服务下线,请求并没有到达。

因此必须在网关中也要定制一层全局异常处理,这样才能更加友好的和客户端交互。

pring Cloud Gateway提供了多种全局处理的方式,今天只介绍其中一种方式,实现还算比较优雅:

直接创建一个类 GlobalErrorExceptionHandler,实现 ErrorWebExceptionHandler,重写其中的 handle 方法,代码如下:

/**
 * 用于网关的全局异常处理
 * @Order(-1):优先级一定要比ResponseStatusExceptionHandler低
 */
@Slf4j
@Order(-1)
@Component
@RequiredArgsConstructor
public class GlobalErrorExceptionHandler implements ErrorWebExceptionHandler {
 
 private final ObjectMapper objectMapper;
 
 @SuppressWarnings({"rawtypes", "unchecked", "NullableProblems"})
 @Override
 public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
  ServerHttpResponse response = exchange.getResponse();
  if (response.isCommitted()) {
   return Mono.error(ex);
  }
 
  // JOSN格式返回
  response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
  if (ex instanceof ResponseStatusException) {
   response.setStatusCode(((ResponseStatusException) ex).getStatus());
  }
 
  return response.writeWith(Mono.fromSupplier(() -> {
   DataBufferFactory bufferFactory = response.bufferFactory();
   try {
    //todo 返回响应结果,根据业务需求,自己定制
    CommonResponse resultMsg = new CommonResponse("500",ex.getMessage(),null);
    return bufferFactory.wrap(objectMapper.writeValueAsBytes(resultMsg));
   }
   catch (JsonProcessingException e) {
    log.error("Error writing response", ex);
    return bufferFactory.wrap(new byte[0]);
   }
  }));
 }
}



6. gateway整合sentinel

https://www.bilibili.com/video/BV1pF41147Aa?p=60&vd_source=61b6fb4e547748656e36b17ee95125fb
https://blog.csdn.net/a745233700/article/details/122917160


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM