SpringCloud微服务实战:nacos+gateway网关统一拦截、转发、授权详细教程(附git源码)

Springboot-cli 开发脚手架系列


文章目录

  • Springboot-cli 开发脚手架系列
  • 简介
    • 1. Springcloud 整合gateway网关
    • 2. yml方式配置转发逻辑
    • 3. 编写两个服务测试效果
    • 4. 统一拦截授权
    • 6. 源码分享


简介

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和Project Reactor等技术。

SpringCloud Gateway是Spring Cloud的一个全新项目,基于Spring 5.0+Spring Boot 2.0和Project Reactor等技术开发的网关,它旨在为微服务架构提供—种简单有效的统一的API路由管理方式。

SpringCloud Gateway作为Spring Cloud 生态系统中的网关,目标是替代Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 1.x非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

SpringCloud Gateway具有如下特性

  • 基于Spring Framework 5,Project Reactor和Spring Boot 2.0进行构建;
  • 动态路由:能够匹配任何请求属性;
  • 可以对路由指定Predicate (断言)和Filter(过滤器);
  • 集成Hystrix的断路器功能;
  • 集成Spring Cloud 服务发现功能;
  • 易于编写的Predicate (断言)和Filter (过滤器);
  • 请求限流功能;
  • 支持路径重写。
    SpringCloud微服务实战:nacos+gateway网关统一拦截、转发、授权详细教程(附git源码)_第1张图片

1. Springcloud 整合gateway网关

  • 环境
spring-cloud.version 2020.0.5
spring-cloud-alibaba.version 2021.1
spring-boot-dependencies.version 2.5.3
  • pom.xml
      <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>

2. yml方式配置转发逻辑

  • 完整配置
server:
  port: 20000
spring:
  application:
    name: gateway
  # NaCos
  cloud:
    service-registry:
      auto-registration:
        # 是否注册到注册中心
        enabled: true
    nacos:
      discovery:
        server-addr: 192.168.41.128:8848
        namespace: 4c016e5c-cacb-44d5-955d-22754ede9fce
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        namespace: ${spring.cloud.nacos.discovery.namespace}
        file-extension: yaml
        prefix: ${spring.application.name}

    #  网关
    gateway:
      default-filters:
        - DedupeResponseHeader=Vary Access-Control-Allow-Credentials Access-Control-Allow-Origin, RETAIN_UNIQUE
        - DedupeResponseHeader=Access-Control-Allow-Origin, RETAIN_FIRST
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true
      routes:
        # 服务1
        - id: server-1
          # 服务地址
          uri: lb://server-1
          # 拦截的路由
          predicates:
            - Path=/server1/**
          # 转发时去除前缀数量,当为1时:原:/server1/a/b/c  转发后为 /a/b/c
          filters:
            - StripPrefix=0
        # 服务2
        - id: server-2
          uri: lb://server-2
          predicates:
            - Path=/server2/**
          filters:
            - StripPrefix=0

  • routes中为数组格式,可配置多个转发逻辑
  • id 可自定义,不重复即可
  • uri配置服务地址 如 lb://+服务名称,我这里以server1server2为例子,也可配置完整地址:uri: http://127.0.0.1:9999
  • predicates 拦截的路由
  • filters 转发时去除前缀数量,当StripPrefix=1时:原:/server1/a/b/c 转发后为 /a/b/c

3. 编写两个服务测试效果

  • server-1
server:
  port: 20001
# NaCos
spring:
  application:
    name: server-1
  # NaCos
  cloud:
    service-registry:
      auto-registration:
        # 是否注册到注册中心
        enabled: true
    nacos:
      discovery:
        server-addr: 192.168.0.251:8848
#        namespace: 4c016e5c-cacb-44d5-955d-22754ede9fce
        namespace: be88b2b8-987c-4801-a5f1-05b867e6370e
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        namespace: ${spring.cloud.nacos.discovery.namespace}
        file-extension: yaml
        prefix: ${spring.application.name}
  • 编写接口服务
@RestController
@Slf4j
@RequestMapping("/server1")
public class IndexController {

    @GetMapping("/get")
    public String get() {
        return "我是服务1";
    }
}

  • 服务2和服务1 创建流程基本一样,这里就不上代码了

  • 最后项目结构如下
    SpringCloud微服务实战:nacos+gateway网关统一拦截、转发、授权详细教程(附git源码)_第2张图片

  • 启动网关和两个测试服务

  • 浏览器输入http://localhost:20000/server1/get
    SpringCloud微服务实战:nacos+gateway网关统一拦截、转发、授权详细教程(附git源码)_第3张图片

  • 浏览器输入http://localhost:20000/server2/get
    SpringCloud微服务实战:nacos+gateway网关统一拦截、转发、授权详细教程(附git源码)_第4张图片

  • 可以发现20000是我们网关的端口,我们通过网关的转发成功的访问了服务1和服务2

4. 统一拦截授权

  • 配置GatewayFilter
/**
 * 网关拦截
 *
 * @author ding
 */
@Component
@Slf4j
public class GatewayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String url = request.getURI().getPath();
        log.info("接收到请求:{}", url);
        // 跨域放行
        if (request.getMethod() == HttpMethod.OPTIONS) {
            response.setStatusCode(HttpStatus.OK);
            return Mono.empty();
        }
        // 授权
        if (!this.auth(exchange, chain)) {
            return this.responseBody(exchange, 406, "请先登录");
        }
        return chain.filter(exchange);
    }

    /**
     * 认证
     */
    private boolean auth(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 逻辑自行实现
        String token = this.getToken(exchange.getRequest());
        log.info("token:{}", token);
        return true;
    }

    /**
     * 获取token
     */
    public String getToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst("token");
        if (StringUtils.isBlank(token)) {
            return request.getQueryParams().getFirst("token");
        }
        return token;
    }

    /**
     * 设置响应体
     **/
    public Mono<Void> responseBody(ServerWebExchange exchange, Integer code, String msg) {
        String message = JSON.toJSONString(new ResponseResult<>(code, msg));
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        return this.responseHeader(exchange).getResponse()
                .writeWith(Flux.just(exchange.getResponse().bufferFactory().wrap(bytes)));
    }

    /**
     * 设置响应体的请求头
     */
    public ServerWebExchange responseHeader(ServerWebExchange exchange) {
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/json");
        return exchange.mutate().response(response).build();
    }

    @Override
    public int getOrder() {
        return -100;
    }

}
  • 当我们再次访问http://localhost:20000/server1/get
  • 观察网关服务的控制台打印可以发现,我们的拦截器已经生效了
    在这里插入图片描述
  • 具体的拦截逻辑可根据自己的业务自行实现,完整的网关授权+OAuth2实现单点登录可参考文末的项目地址,有完整源码参考。

6. 源码分享

本项目已收录

  • Springboot、SpringCloud各种常用框架使用案例,完善的文档,致力于让开发者快速搭建基础环境并让应用跑起来,并提供丰富的使用示例供使用者参考,快速上手。
  • 项目源码github地址
  • 项目源码国内gitee地址

你可能感兴趣的:(SpringCloud实战,SpringBoot-cli,开发脚手架,spring,cloud,微服务,gateway,springboot,nacos)