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

Springboot-cli 软件系统定制开发开发脚手架系列


文章目录


简介

Gateway是在Spring软件系统定制开发生态系统之上构建的网关服务,基于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 (过滤器);
  • 请求限流功能;
  • 支持路径重写。

1. Springcloud 整合gateway网关

  • 环境
spring-cloud.version 2020.0.5spring-cloud-alibaba.version 2021.1spring-boot-dependencies.version 2.5.3
  • 1
  • 2
  • 3
  • pom.xml
      <dependency>            <groupId>org.springframework.cloud</groupId>            <artifactId>spring-cloud-starter-gateway</artifactId>        </dependency>
  • 1
  • 2
  • 3
  • 4

2. yml方式配置转发逻辑

  • 完整配置
server:  port: 20000spring:  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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 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# NaCosspring:  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}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 编写接口服务
@RestController@Slf4j@RequestMapping("/server1")public class IndexController {    @GetMapping("/get")    public String get() {        return "我是服务1";    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 服务2和服务1 创建流程基本一样,这里就不上代码了

  • 最后项目结构如下

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

  • 浏览器输入http://localhost:20000/server1/get

  • 浏览器输入http://localhost:20000/server2/get

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

4. 统一拦截授权

  • 配置GatewayFilter
/** * 网关拦截 * * @author ding */@Component@Slf4jpublic 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;    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 当我们再次访问http://localhost:20000/server1/get
  • 观察网关服务的控制台打印可以发现,我们的拦截器已经生效了
  • 具体的拦截逻辑可根据自己的业务自行实现,完整的网关授权+OAuth2实现单点登录可参考文末的项目地址,有完整源码参考。

6. 分享

本项目已收录

  • Springboot、SpringCloud各种常用框架使用案例,完善的文档,致力于让开发者快速搭建基础环境并让应用跑起来,并提供丰富的使用示例供使用者参考,快速上手。
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发