我在使用Spring Gateway时遇到的一些坑

前言

最近在公司用Spring Cloud 全家桶搭建一套完整的微服务,在网关选型的时候,由于咱们公司可能会用到websocket,因此放弃zuul而改用Spring Cloud Gateway,本文记录下在使用gateway过程当中遇到的一些坑和注意点。html

正文

Gateway的介绍和基本的搭建就不说了,能够按照官方文档走。Spring Cloud Gateway和zuul的区别也不提了,网上也有不少文章。使用gateway直接引入依赖就行,不用在启动类加注解。linux

1. 请求转发

我在这里把请求转发大概的分红两类:nginx

a.未整合注册中心

其实这种用法比较少,通常来讲咱们都会整合注册中心使用,这样能够达到自动配置自动转发。固然这种特定的方式也许某些场合也会用到。web

这种状况下就须要你指定你须要转发到哪一个服务器上去,这边能够分为两种,配置文件和代码形式。spring

a.1 配置文件docker

来个样例api

spring:
  application:
    name: spring-cloud-gateway-sample
  cloud:
    gateway:
      routes:
        - id: blog
          uri: http://juejin.im
          predicates:
            # 匹配路径转发
            - Path=/api-boot-datasource-switch.html
# 端口号
server:
  port: 9090
复制代码

几个名词, id是目前所写的路由的id,id前面有个 -, 这是yml的写法,至关于一个list的多个元素,你能够写多个路由,用-id 来区别开来。跨域

uri就是你须要转发的地址了。由于没有整合注册中心因此须要写全。bash

这里解释下 Predicates吧,每个Predicate的使用,你能够理解为:当知足这种条件后才会被转发,若是是多个,那就是都知足的状况下被转发。好比上面的例子就是当访问http://localhost:9090/api-boot-datasource-switch.html时就会被自动转发到http://juejin.im/api-boot-datasource-switch.html,这里要注意彻底匹配Path的值时才会进行路由转发。服务器

因此上面的例子是谓词Path的样例,还有不少谓词,好比 Before, After,Cookie, Header, Host等等,他们也能够组合出现。 全面的你能够参考官方文档或者这篇文章,写的也比较全面:www.jianshu.com/p/d2c3b6851…

a.2 RouteLocator

代码的形式能够经过 RouteLocator 类来实现:

@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
  return builder.routes()
    .route("blog", r -> 
           r.path("/api-boot-datasource-switch.html").uri("http://juejin.im"))
    .build();
}
复制代码

这个就是上面使用Path谓词的代码体现,讲这个类以@Bean的形式注入到spring中就行。其余的谓词相似,不提了。

b.整合注册中心

这个实际上是平常工做中比较经常使用的,这里我是用的eureka,其余的注册中心应该相似。

这里我用了配置文件的方式实现了全局的配置,

spring:
  application:
    name: spring-cloud-gateway-sample
  cloud:
    gateway:
      routes:
        - id: blog
          uri: lb://blog-service
          predicates:
            # 匹配路径转发
            - Path=/blog/**
# 端口号
server:
  port: 9090
复制代码

上面的例子和配置未整合时的yml相似,惟一不一样的就是 uri的配置和Path的条件,这里使用了 lb:// 的形式,表明从注册中心获取服务,后面接的就是你须要转发到的服务名称,这个服务名称必须跟eureka中的对应,不然会找不到服务。因此上面的配置文件就是当你的请求路径端口号后以/blog开头的都转发到 blog-serivce上去,参数不变。

第二种就是我比较推荐的,默认全局的配置,只要你的路径中以微服务的服务名称开头,都会自动转发到该服务上去。 配置以下

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lowerCaseServiceId: true

复制代码

配置完成以后咱们就能够经过小写的服务名称进行访问了,好比 https://gatewayIp:gatewayPort/blog/article/all 就会自动转发到 http://blogserviceIp:blogservicePort/article/all

2. 跨域

这个问题,你在其余平台几乎能够看到千篇一概的解决方案而且亲自实践后发现并无起到做用(多是gateway自升级后这些解法已经不支持,至少我亲自实践后确实不起做用)。不过我仍是遇到了一种比较好的写法,可以合理的解决跨域的问题,亲测有效。若是有更好的解法也欢迎分享。

贴上原文连接: blog.csdn.net/xht555/arti…

另外还有一个,实践后没有起到做用,也贴出来你们参考下:www.jianshu.com/p/a46e62f9a…

3. docker容器

我司用docker容器来做为微服务的linux容器,当容器和spring cloud eureka结合的时候,会遇到一个坑,这是我在使用zuul网关请求的时候就遇到的。

Zuul在转发请求的时候,会根据eureka注册表里的各个微服务的ip+port去寻找地址,可是坑爹的是,当你的微服务在docker容器中时,注册进去的形式是 docker容器ID + port, 相似于你在eureka的监控面板看到的是 R3FDS4G:8080,这样你的网关在请求转发的时候,会报 server unknow 的错误,并且这个问题在本地是不存在的由于你本地一直都是localhost。

解决办法是,在你的eureka client的配置文件中,将你的server 以ip+port的形式注册进去。

eureka:
  instance:
    prefer-ip-address: true
    instance-id: ${spring.cloud.client.ip-address}:${server.port}:${spring.application.name}
复制代码

好了,当你成功的将你的容器以ip+port的形式注册到eureka中时,这时候仍是有问题,虽然网关可以成功的将请求转发,可是这个时候是ping不通的,你点开eureka的监控面板,能够发现,此时微服务的ip地址并非宿主机的地址。这个其实就要说到docker通讯问题了,docker默认的是bridge模式,容器会本身在内部开辟空间,外部是链接不通的。因此docker启动的时候,须要在命令行里加上 -net=host,这样容器就会挂载到宿主机上了。关于docker通讯问题能够自行查阅资料。这个时候网关就能成功的转发请求了(指的是整个注册中心)。 若是你使用网关转发的时候已经指定了微服务的服务器路径,那就不会出现上述问题的,只是你每多加一个微服务可能就要再次配置一遍。

总结

以上就是我在工做中遇到的一些问题,之后还有问题会更新。

Spring cloud gateway感受国内用的还很少,大厂基本自研,小公司又不多用到spring cloud网关组件或者直接nginx作网关,若是有问题能够去GitHub直接和做者聊聊。

相关文章
相关标签/搜索