SpringCloudAlibaba Gateway(一)简单集成

SpringCloudAlibaba Gateway(一)简单集成

随着服务模块的增加,一定会产生多个接口地址,那么客户端调用多个接口只能使用多个地址,维护多个地址是很不方便的,这个时候就需要统一服务地址。同时也可以进行统一认证鉴权的需求。那么服务网关就充当这样的角色。

Gateway

​ 网关为众多微服务挡在前面,做路由转发、监控、限流、鉴权等功能。SpringCloudGateway就是其实现之一。SpringCloudGateway借鉴了Spring Cloud Netfilix Zuul的思想,它的目标是替代Zuul。

Gateway是基于WebFlux框架实现的,而WebFlux底层是使用高性能框架Netty,性能方面是Zuul的1.6倍,且功能强大,设计优雅。

​ Gateway的核心是路由Predicate(断言)Filter(过滤器)。路由是转发规则,Predicate是判断,Filter可以认为是请求被路由前或后加一点自定义逻辑。

SpringCloudGateway需要使用SpringBoot2.0+及以上版本,并且不可以在Tomcat或Jetty等Servlet容器运行,必须是Jar包运行!!!

集成Gateway

构建一个Gateway网关服务,再创建两个服务:用户服务和商品服务,架构如下:

user服务UserController,用户服务端口8002

java 复制代码
@RestController
public class UserController {
    private final Map<Integer, String> userInfo = new HashMap<Integer, String>() {{
        put(1, "Zhangsan");
        put(2, "Lisi");
    }};
    @RequestMapping("/user/findById")
    public String findById(@RequestParam("id") Integer id) {
        return userInfo.getOrDefault(id, null);
    }
}

shop服务ShopController,商品服务端口8003

java 复制代码
@RestController
public class ShopController {
    private final Map<Integer, String> shopInfo = new HashMap<Integer, String>() {{
        put(1, "这是苹果");
        put(1024, "芒果");
    }};
    @RequestMapping("/shop/findById")
    public String findById(@RequestParam("id") Integer id) {
        return shopInfo.getOrDefault(id, null);
    }
}

创建一个gateway的服务

依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Gateway中去除spring-boot-starter-web依赖,gateway中有webflux依赖,与starter-web有冲突。

bootstrap.yml加入配置

yml 复制代码
server:
  port: 8083

spring:
  application:
    name: gateway   # 服务名
  
  cloud:
    gateway:
	  routes: # 路由,可配置多个
        - id: user_route  # 路由id,唯一即可,默认UUID
          uri: http://localhost:8002  # 路由地址(匹配成功后的服务地址)
          order: 1  # 路由优先级,默认0,越低优先级越高
          predicates:
            - Path=/user/**   # 断言,匹配规则

        - id: shop_route
          uri: http://localhost:8003
          order: 1
          predicates:
          - Path=/shop/**

网关配置也可以使用JavaConfig的方式,但是不推荐使用。

配置中表示,当请求网关路径中地址是以/user/开头就路由到用户服务中,/shop/开头路由到商品服务中。

测试一下

shell 复制代码
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
Zhangsan
C:\Users\Admin>curl http://localhost:8083/shop/findById?id=1024
芒果

Gateway整合nacos

上面案例中,uri都是写死的一些东西,如果对应的具体服务地址改了,那么就需要修改配置文件,而且假如要提高用户承载量,做负载均衡,有很多个节点,肯定不能只配置一个服务地址。

那么就需要用到nacos,统一管理服务注册、发现,网关路由转发的地址从nacos中拿就行。

那么用户服务商品服务需要引入nacos服务发现注册依赖

xml 复制代码
<!-- 服务注册  服务发现需要引入的 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!--健康监控-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

bootstrap.yml文件

yml 复制代码
------------------------User服务
server:
  port: 8002
spring:
  application:
    name: user # 应用名

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址
        
--------------------------Shop服务
server:
  port: 8003
spring:
  application:
    name: shop # 应用名

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址

最后记得启动类上,启动nacos服务注册发现

java 复制代码
@SpringBootApplication
@EnableDiscoveryClient	// 启用服务注册发现
public class UserApp {

    public static void main(String[] args) {
        SpringApplication.run(UserApp.class, args);
    }
}

欧克,那么同样地,gateway服务也要启用服务注册发现

依赖

xml 复制代码
<!-- 服务注册  服务发现需要引入的 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

bootstrap.yml配置如下:

yml 复制代码
server:
  port: 8083

spring:
  application:
    name: gateway   # 服务名

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos地址
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的服务,gateway自动根据服务发现为每一个服务创建了一个router,# 这个router将以服务名开头的请求路径转发到对应的服务
      routes: # 路由,可配置多个
      - id: user_route  # 路由id,唯一即可,默认UUID
        uri: lb://user  # 路由地址(匹配成功后的服务地址) user是用户服务的服务名称
        order: 1  # 路由优先级,默认0,越低优先级越高
        predicates:
        - Path=/user/**   # 断言,匹配规则

      - id: shop_route
        uri: lb://shop  # 路由地址(匹配成功后的服务地址) shop是商品服务的服务名称
        order: 1
        predicates:
        - Path=/shop/**

启动尝试下:

shell 复制代码
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
{"timestamp":"2023-08-05T00:34:40.684+00:00","path":"/user/findById","status":503,"error":"Service Unavailable","requestId":"f5f6d217-1"}
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
{"timestamp":"2023-08-05T00:35:50.223+00:00","path":"/user/findById","status":503,"error":"Service Unavailable","requestId":"21a722a2-1"}

哈?服务不可用,经查阅资料得知:缺少ReactiveLoadBalancerClientFilter过滤器,需要LoadBalancerClientFactory类,但是需要引入相关依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

可以了,再试下:

shell 复制代码
C:\Users\Admin>curl http://localhost:8083/shop/findById?id=1024
{"timestamp":"2023-08-05T01:19:34.183+00:00","status":404,"error":"Not Found","path":"/findById"}
C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
{"timestamp":"2023-08-05T01:19:34.183+00:00","status":404,"error":"Not Found","path":"/findById"}

好嘞漂亮,踩了大坑了!!!一直404!!!

经过百般挣扎,查资料,看源码,调试等等手段,明白原因了...

yml 复制代码
spring:
  application:
    name: gateway   # 服务名
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos地址
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的服务,gateway自动根据服务发现为每一个服务创建了一个router,# 这个router将以服务名开头的请求路径转发到对应的服务

重点来了注意看:

当你的gateway配置了locator.enabled: true时,gateway自动根据服务发现为每一个服务创建了一个router, 这个router将以服务名开头的请求路径转发到对应的服务,相当于人家给你自动生成了route规则,你自己都不用配置了

但是:你的请求中必须要带着服务端的服务名才可以进行访问到

以上述为例:如果要访问到user服务的/user/findById,那么请求地址为localhost:8083/user/user/findById

shell 复制代码
C:\Users\Admin>curl http://localhost:8083/user/user/findById?id=1
Zhangsan

如何选择

提供两种写法:

  • 实际上,如果项目路径比较简单,直接让gateway和nacos自动生成即可

    yml 复制代码
    spring:
      application:
        name: gateway   # 服务名
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 # nacos地址
        gateway:
          discovery:
            locator:
              enabled: true # 让gateway可以发现nacos中的服务,gateway自动根据服务发现为每一个服务创建了一个router,# 这个router将以服务名开头的请求路径转发到对应的服务

    请求时,记得带上服务端的application.name名称即可,如locahost:8083/user/user/findById,第一个user是服务名称

  • 假如不想这么做,想直接以一个路径,跳到对应的服务中去,不去写服务名,那么我们需要自定义routes

    yml 复制代码
    server:
      port: 8083
    
    spring:
      application:
        name: gateway   # 服务名
    
      cloud:
        nacos:
          discovery:
            server-addr: localhost:8848 # nacos地址
        gateway:
          routes: # 路由,可配置多个
          - id: user_route  # 路由id,唯一即可,默认UUID
            uri: lb://user  # 路由地址(匹配成功后的服务地址) user是用户服务的服务名称
            order: 1  # 路由优先级,默认0,越低优先级越高
            predicates:
            - Path=/user/**   # 断言,匹配规则

    不使用nacos自动生成的routes,自己定义,那么我们访问时localhost:8083/user/findById就能正常访问到user服务下的/user/findById资源了。

    shell 复制代码
    C:\Users\Admin>curl http://localhost:8083/user/findById?id=1
    Zhangsan

两种方式都可以使用,根据项目的实际情况选择。locator.enabled: true只要在gateway中配置了,那么你在进行网关路由时,请求地址的第一个目录一定是服务名称

相关推荐
茶馆大橘10 小时前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud
牛角上的男孩15 小时前
Istio Gateway发布服务
云原生·gateway·istio
WANT_如初2 天前
Nacos集群搭建
java·springcloud·nacos集群
柳叶寒3 天前
医院信息化与智能化系统(17)
java·nacos·gateway·全栈·项目
cyt涛3 天前
SpringCloudGateway — 网关路由
java·开发语言·网关·gateway·路由·断言·转发
茶馆大橘5 天前
微服务系列三:微服务核心——网关路由
java·运维·网关·微服务·架构·springcloud
代码魔法师Sunny5 天前
502 Bad Gateway 错误详解:从表现推测原因,逐步排查直至解决
gateway
xxxLin6 天前
OpenFeign简单使用
springcloud
RedCong6 天前
通过route访问Openshift上的HTTP request报错504 Gateway Time-out【已解决】
http·gateway·openshift