温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何进行第二代网关GateWay的搭建

发布时间:2021-11-11 09:55:56 来源:亿速云 阅读:154 作者:柒染 栏目:编程语言

如何进行第二代网关GateWay的搭建,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

Spring Cloud第二代网关GateWay是由纯Netty开发,底层为Reactor,WebFlux构建,不依赖任何Servlet容器,它不同于Zuul,使用的是异步IO,性能较Zuul提升1.6倍。搭建过程如下(本次搭建的为子项目,主项目可以参考Nacos搭建流程 )

pom

<dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-starter-gateway</artifactId></dependency><dependency>   <groupId>com.alibaba.cloud</groupId>   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>

配置文件

server:  port: 8040spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      discovery:        locator:          enabled: true

以上的意思不仅是把自己给注册到nacos,并且获取nacos的所有注册服务。

启动网关项目,现在就可以进行网络路由了。访问格式为 ip:端口/服务注册名/restfulapi-url

比方说我们现在有两个微服务项目,一个为user(端口8082),一个为nacos(端口8081).

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

三大核心概念

  • Route(路由) Spring Cloud Gateway的基础元素,可简单理解成一条转发的规则。包含:ID,目标的URL,Predicate集合以及Filter集合。

  • Predicate(谓词) 即java.util.function.Predicate,Spring Cloud Gateway使用Predicate实现路由的匹配条件。这是一个可以进行条件判断的函数式接口,具体可以参考本人博客Java函数式编程整理

  • Filter(过滤器) 修改请求以及响应。

由于我们使用了nacos来进行服务发现,所以我们使用了之前的配置文件,但如果不使用服务发现,只做常规的转发如下

spring:
  cloud:gateway:  routes:        - id: some_route          uri: http://www.baidu.com          predicates:            - Path=/user/1          filtes:            - AddRequestHeader=X-Request-Foo, Bar

这段配置的意思是说,当我们请求/user/1的url的时候,会添加AddRequestHeader=X-Request-Foo, Bar过滤器做一些处理,然后路由到http://www.baidu.com。

路由谓词配置工厂

路由谓词配置工厂由一整套谓词来进行配置转发的不同情况。

谓词工厂备注
After此谓词匹配当前日期时间之后发生的请求。
Before此谓词匹配在当前日期时间之前发生的请求。
Between此谓词匹配datetime1之后和datetime2之前发生的请求。 datetime2参数必须在datetime1之后。
CookieCookie Route Predicate Factory有两个参数,cookie名称和正则表达式。此谓词匹配具有给定名称且值与正则表达式匹配的cookie。
HeaderHeader Route Predicate Factory有两个参数,标题名称和正则表达式。与具有给定名称且值与正则表达式匹配的标头匹配。
HostHost Route Predicate Factory采用一个参数:主机名模式。该模式是一种Ant样式模式“.”作为分隔符。此谓词匹配与模式匹配的Host标头。
MethodMethod Route Predicate Factory采用一个参数:要匹配的HTTP方法。
Path匹配请求的path
QueryQuery Route Predicate Factory有两个参数:一个必需的参数和一个可选的正则表达式。
RemoteAddrRemoteAddr Route Predicate Factory采用CIDR符号(IPv4或IPv6)字符串的列表(最小值为1),例如, 192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。

路由到指定URL

  • 通配

现在我们去掉nacos的配置,不由nacos来发现

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**filters:        #跳转后省略第一个通配        - StripPrefix=1

此时访问

如何进行第二代网关GateWay的搭建

将跳转到

如何进行第二代网关GateWay的搭建

  • 谓词After

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#在2019-12-14日20:26后允许该转发        - After=2019-12-14T20:26:15.667+08:00[Asia/Shanghai]filters:        #跳转后省略第一个通配        - StripPrefix=1

这里表示在该时间后允许转发,如果我们将该时间设置为

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#在2019-12-15日20:26后允许该转发        - After=2019-12-15T20:26:15.667+08:00[Asia/Shanghai]filters:        #跳转后省略第一个通配        - StripPrefix=1

则转发失败,返回404

如何进行第二代网关GateWay的搭建

我们可以通过以下方法来获取这里的时间设置

public class TimeTest {public static void main(String[] args) {
        System.out.println(ZonedDateTime.now());    }
}

运行结果

2019-12-14T20:43:34.755+08:00[Asia/Shanghai]

  • 谓词Before

现在我们将上面的15号改为Before

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#在2019-12-15日20:26前允许该转发        - Before=2019-12-15T20:26:15.667+08:00[Asia/Shanghai]filters:        #跳转后省略第一个通配        - StripPrefix=1

此时就可以正常转发,而改成14号则会失败。

  • 谓词Between

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#在2019-12-14日20:26到2019-12-15日20:26之间允许该转发        - Between=2019-12-14T20:26:15.667+08:00[Asia/Shanghai],2019-12-15T20:26:15.667+08:00[Asia/Shanghai]filters:        #跳转后省略第一个通配        - StripPrefix=1
  • 谓词Cookie

我们在user模块增加一个带cookie的Controller

@Slf4j@RestControllerpublic class CookieController {@GetMapping("/welcome")public Boolean handle(HttpServletRequest request,                               HttpServletResponse response) throws Exception {
        Cookie cookie = new Cookie("test","value");        cookie.setMaxAge(Integer.MAX_VALUE);        response.addCookie(cookie);        log.info("welcome");        return true;    }
}

此时我们访问该Controller为

如何进行第二代网关GateWay的搭建

此时网关这边配置为

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#只有带上Cookie名为test,并且值符合正则value的cookie时,才允许被转发        - Cookie=test,valuefilters:        #跳转后省略第一个通配        - StripPrefix=1

如何进行第二代网关GateWay的搭建

  • 谓词Header

现在我们给user模块添加一个Controller的方法

@GetMapping("/header")public String header(@RequestHeader("item") String item) {return item;}

我们通过postman给该方法的访问添加请求头

如何进行第二代网关GateWay的搭建

在网关中的配置为

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#只有带上请求头名为item,并且值符合正则123.p,才会转发        - Header=item,123.pfilters:        #跳转后省略第一个通配        - StripPrefix=1

如何进行第二代网关GateWay的搭建

这里正则.可以匹配一个单字符

如果我们在请求头item中设置错误的字符则无法转发

如何进行第二代网关GateWay的搭建

  • 谓词Host

要配置Host,我们需要给服务器的hosts文件添加一个域名映射,当然在互联网上需要一个域名来做DNS解析。

我这里给自己的域名添加为local.register.com

访问user的find方法

如何进行第二代网关GateWay的搭建

给网关添加配置

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#只有带上请求头Host,且值匹配**.register.com:8040才能通过转发        - Host=**.register.com:8040filters:        #跳转后省略第一个通配        - StripPrefix=1

此时我们通过网关访问如下

如何进行第二代网关GateWay的搭建

  • 谓词Method

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#只有当HTTP请求方法是GET时才能转发        - Method=GETfilters:        #跳转后省略第一个通配        - StripPrefix=1
  • 谓词Query

现在我们给user模块增加一个Controller方法

@GetMapping("/query")public String query(@RequestParam("name") String name) {return name;}

访问如下

如何进行第二代网关GateWay的搭建

网关配置如下

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#只有当请求带上参数名称为name时才能通过转发        - Query=namefilters:        #跳转后省略第一个通配        - StripPrefix=1

如何进行第二代网关GateWay的搭建

如果不带上该参数则无法转发,如

如何进行第二代网关GateWay的搭建

  • 谓词RemoteAddr

spring:  application:    name: gateway  cloud:    gateway:      routes:      - id: gateuri: http://127.0.0.1:8082predicates:        #由/user来匹配跳转        - Path=/user/**#只有当请求为192.168.20.1/24网段(IP地址从192.168.20.1到192.168.20.254)才会转发        - RemoteAddr=192.168.20.1/24filters:        #跳转后省略第一个通配        - StripPrefix=1

例如

如何进行第二代网关GateWay的搭建

但是使用127.0.0.1却无法访问

如何进行第二代网关GateWay的搭建

现在我们恢复nacos的服务发现

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1

为了跟不做任何配置相区别,我们这里谓词Path写了user-center

如何进行第二代网关GateWay的搭建

自定义路由谓词工厂

假设现在我们的一个API只有在上午9点到下午5点允许转发

配置的文件如下

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**
        - TimeBetween=上午9:00,下午5:00filters:        #跳转后省略第一个通配        - StripPrefix=1

由于这个TimeBetween并不是gateway默认的谓词工厂,所以我们需要自己来实现一个谓词工厂,我们先定义一个时间的配置类

@Datapublic class TimeBetweenConfig {private LocalTime start;    private LocalTime end;}

然后自定义一个谓词工厂类,该工厂类名称必须以自定义谓词开头(这里是TimeBetween),以RoutePredicateFactory结尾,并继承AbstractRoutePredicateFactory抽象类

@Componentpublic class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenConfig>{public TimeBetweenRoutePredicateFactory() {super(TimeBetweenConfig.class);    }@Override    public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {
        LocalTime start = config.getStart();        LocalTime end = config.getEnd();        return exchange -> {
            LocalTime now = LocalTime.now();            return now.isAfter(start) && now.isBefore(end);        };    }@Override    public List<String> shortcutFieldOrder() {return Arrays.asList("start","end");    }
}

内置过滤器工厂

1 AddRequestHeader GatewayFilter Factory
2 AddRequestParameter GatewayFilter Factory
3 AddResponseHeader GatewayFilter Factory
4 DedupeResponseHeader GatewayFilter Factory
5 Hystrix GatewayFilter Factory
6 FallbackHeaders GatewayFilter Factory

7 PrefixPath GatewayFilter Factory

8 PreserveHostHeader GatewayFilter Factory
9 RequestRateLimiter GatewayFilter Factory
10 RedirectTo GatewayFilter Factory
11 RemoveHopByHopHeadersFilter GatewayFilter Factory
12 RemoveRequestHeader GatewayFilter Factory
13 RemoveResponseHeader GatewayFilter Factory
14 RewritePath GatewayFilter Factory
15 RewriteResponseHeader GatewayFilter Factory
16 SaveSession GatewayFilter Factory
17 SecureHeaders GatewayFilter Factory
18 SetPath GatewayFilter Factory
19 SetResponseHeader GatewayFilter Factory
20 SetStatus GatewayFilter Factory
21 StripPrefix GatewayFilter Factory
22 Retry GatewayFilter Factory
23 RequestSize GatewayFilter Factory
24 Modify Request Body GatewayFilter Factory
25 Modify Response Body GatewayFilter Factory
26 Default Filters

  • AddRequestHeader

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 192.168.10.172:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#增加一个名称为X-Request-Foo,值为Bar的请求头        - AddRequestHeader=X-Request-Foo,Bar

这里需要注意的是新增的这个请求头是转发以后添加进去的,所以我们请求网关的时候在浏览器中是找不到的,我们可以使用command+N(Windows中idea为Ctrl+N)来查找NettyRoutingFilter类,并且在filter方法中设置断点,由以下图中可以看到它是被添加进去了。

如何进行第二代网关GateWay的搭建

  • AddRequestParameter

由于在user模块中有这么一个方法

@GetMapping("/query")public String query(@RequestParam("name") String name) {return name;}

所以我们在网关配置时

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#增加一个名称为name,值为locky的请求参数        - AddRequestParameter=name,locky

所以我们在网关中请求就可以不写参数,直接访问

如何进行第二代网关GateWay的搭建

  • AddResponseHeader

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#增加一个名称为X-Response-Foo,值为Bar的响应头        - AddResponseHeader=X-Response-Foo, Bar

如何进行第二代网关GateWay的搭建

  • DedupeResponseHeader

Spring Cloud Greenwich SR2提供的新特性,低于这个版本无法使用。
它的主要作用是去重,例如

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**
        - Cookie=test,valuefilters:        #跳转后省略第一个通配        - StripPrefix=1#在Http响应报文头中进行去重,去重目标为跨域请求        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
  • Hystrix

Hystrix是Spring Cloud第一代中的容错组件,不过已经进入维护模式。未来,Hystrix会被Spring Cloud移除掉,取而代之的是Alibaba Sentinel/Resilience4J。

此处不做具体设置了

  • FallbackHeaders

也是对Hystrix的支持,不做具体设置了

  • PrefixPath

为匹配的路由添加前缀,我们在user模块的find添加一层访问路径

@GetMapping("/test/find")@SuppressWarnings("unchecked")public Result<User> findStr() {log.info("访问成功");    return Result.success(new User(1,"张三",23));}

网关配置

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#跳转后添加前缀/test        - PrefixPath=/test

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

一致。

  • PreserveHostHeader

如果不设置,那么名为 Host 的Header由Http Client控制;如果设置了,那么会设置一个请求属性(preserveHostHeader=true),路由过滤器会检查从而去判断是否要发送原始的、名为Host的Header。这里主要是通过网关是否向代理服务器转发请求头中的Host属性。

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#转发客户端的请求报文头Host给后端代理服务器        - PreserveHostHeader
  • RequestRateLimiter

Gateway自带的限流服务,但后续我们会整合Gateway和Sentinel来进行限流和熔断。

  • RedirectTo

转发到后端服务后再重定向到一个url.

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#转发到Path,并且携带一个http://www.baidu.com到Location的响应头        - RedirectTo=302,http://www.baidu.com

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

从以上图中可以看出,其实我们请求的是http://127.0.0.1:8040/user-center/find,但是被重定向到了百度。这里HTTP状态码应该是HTTP状态码300序列,例如301.302,具体状态码可以参考HTTP协议整理

  • RemoveHopByHopHeadersFilter

移除转发请求的Header,多个用","分隔。默认情况下移除如下Header。

  1. Connection

  2. Keep-Alive

  3. Proxy-Authenticate

  4. Proxy-Authorization

  5. TE

  6. Trailer

  7. Transfer-Encoding

  8. Upgrade

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1      filter:        #移除转发请求        remove-hop-by-hop:          headers: Keep-Alive,Connection
  • RemoveRequestHeader

移除原始请求头

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#移除原始请求头X-Request-Foo        - RemoveRequestHeader=X-Request-Foo

由spring cloud zuul网关的作用 可知,在跨域转发中,我们需要移除这些请求头

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#移除原始跨域请求头        - RemoveRequestHeader=Access-Control-Allow-Origin      filter:        #移除转发请求        remove-hop-by-hop:          headers: Access-Control-Allow-Credentials,Access-Control-Allow-Origin,Vary,X-Frame-Options,token
  • RemoveResponseHeader

移除响应头

我们在user中添加一个Controller方法

@GetMapping("/addhead")public String addHeader(HttpServletRequest request, HttpServletResponse response) {
    response.addHeader("X-Response-Foo","Foo");    return "header";}

如何进行第二代网关GateWay的搭建

网关配置

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#移除响应头X-Response-Foo        - RemoveResponseHeader=X-Response-Foo

如何进行第二代网关GateWay的搭建

通过网关转发,我们可以看到无此X-Response-Foo的响应头。

  • RewritePath

重写请求路径

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #配置成原始路径正则, 重写后的路径的正则        - RewritePath=/user-center/(?<segment>.*), /$\{segment}

以上配置会将/user-center/find变成/find再转发

直接访问user

如何进行第二代网关GateWay的搭建

网关请求的

如何进行第二代网关GateWay的搭建

  • RewriteResponseHeader

重写响应头部分内容,根据正则来修改

之前在user中有一个Controller方法

@GetMapping("/addhead")public String addHeader(HttpServletRequest request, HttpServletResponse response) {
    response.addHeader("X-Response-Foo","Foo");    return "header";}
spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#重写响应头X-Response-Foo的值Foo为dee,内容可根据正则匹配        - RewriteResponseHeader=X-Response-Foo,Foo,dee

访问user的/addhead,X-Response-Foo响应头的值为Foo.

如何进行第二代网关GateWay的搭建

通过网关访问/addhead,X-Response-Foo响应头的值为dee

如何进行第二代网关GateWay的搭建

  • SaveSession

在转发到后端微服务请求之前,强制执行 WebSession::save 操作。用在那种像 Spring Session 延迟数据存储(数据不是立刻持久化)的,并希望在请求转发前确保session状态保存情况。

现在我们对user进行共享Session的配置,添加依赖

<dependency>   <groupId>org.springframework.boot</groupId>   <artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency>   <groupId>org.springframework.session</groupId>   <artifactId>spring-session-data-redis</artifactId></dependency><dependency>   <groupId>redis.clients</groupId>   <artifactId>jedis</artifactId>   <version>2.9.0</version></dependency>

添加配置

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    password: xxxxx
    timeout: 10000
    lettuce:
      pool:
        min-idle: 0
        max-idle: 8
        max-active: 8
        max-wait: -1

在SpringBoot开启共享Session

@EnableRedisHttpSession@SpringBootApplicationpublic class UserApplication {   public static void main(String[] args) {
      SpringApplication.run(UserApplication.class, args);   }

}

在user中添加如下Controller

@RestControllerpublic class SessionController {@GetMapping("/first")public Map<String,Object> firstResp(HttpServletRequest request, HttpServletResponse response) {
        Map<String,Object> map = new HashMap<>();        request.getSession().setAttribute("request Url",request.getRequestURL());        map.put("request Url",request.getRequestURL());        return map;    }@GetMapping("/sessions")public Object sessions(HttpServletRequest request,HttpServletResponse response) {
        Map<String,Object> map = new HashMap<>();        map.put("SessionId",request.getSession().getId());        map.put("message",request.getSession().getAttribute("request Url"));        return map;    }
}

我们启动两个user实例,一个端口号为8082,一个为8083,访问如下

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

我们可以看到除了存入Session的RequestURL不同以外,他们的SessionId是相同的,说明这里是一个共享的Session。

我们不对网关配置做修改,则我们通过网关访问

如何进行第二代网关GateWay的搭建

如何进行第二代网关GateWay的搭建

在访问first的时候,它会负载均衡这两个实例,但我们可以看到他在Session中存储的是内网的IP,而不是127.0.0.1。

如何进行第二代网关GateWay的搭建

在网关做如下配置

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#请求转发前保存Session        - SaveSession

目前未测出有什么太大的作用。反而会破坏Session的数据。所以不建议增加该设置。

  • SecureHeaders

添加一系列起安全作用的响应头。

默认会添加如下Header(包括值):

  1. X-Xss-Protection:1; mode=block 防XSS攻击设置,0: 表示关闭浏览器的XSS防护机制;1:删除检测到的恶意代码, 如果响应报文中没有看到X-XSS-Protection 字段,那么浏览器就认为X-XSS-Protection配置为1,这是浏览器的默认设置.1; mode=block:如果检测到恶意代码,在不渲染恶意代码.

  2. Strict-Transport-Security:max-age=631138519 一个网站接受一个HTTP的请求,然后跳转到HTTPS,用户可能在开始跳转前,通过没有加密的方式和服务器对话,比如,用户输入http://foo.com或者直接foo.com。这样存在中间人攻击潜在威胁,跳转过程可能被恶意网站利用来直接接触用户信息,而不是原来的加密信息。网站通过HTTP Strict Transport Security通知浏览器,这个网站禁止使用HTTP方式加载,浏览器应该自动把所有尝试使用HTTP的请求自动替换为HTTPS请求。

  3. X-Frame-Options:DENY 点击劫持(ClickJacking)是一种视觉上的欺骗手段。攻击者使用一个透明的iframe,覆盖在一个网页上,然后诱使用户在网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。
    HTTP响应头信息中的X-Frame-Options,可以指示浏览器是否应该加载一个iframe中的页面。如果服务器响应头信息中没有X-Frame-Options,则该网站存在ClickJacking攻击风险。网站可以通过设置X-Frame-Options阻止站点内的页面被其他页面嵌入从而防止点击劫持。
    解决方案:
    修改web服务器配置,添加X-Frame-Options响应头。赋值有如下三种:
    1、DENY:不能被嵌入到任何iframe或者frame中。
    2、SAMEORIGIN:页面只能被本站页面嵌入到iframe或者frame中
    3、ALLOW-FROM uri:只能被嵌入到指定域名的框架中

  4. X-Content-Type-Options:nosniff

    如果服务器发送响应头 "X-Content-Type-Options: nosniff",则 script 和 styleSheet 元素会拒绝包含错误的 MIME 类型的响应。这是一种安全功能,有助于防止基于 MIME 类型混淆的攻击。

     

    简单理解为:通过设置"X-Content-Type-Options: nosniff"响应标头,对 script 和 styleSheet 在执行是通过MIME 类型来过滤掉不安全的文件

    服务器发送含有 "X-Content-Type-Options: nosniff" 标头的响应时,此更改会影响浏览器的行为。

  5. Referrer-Policy:no-referrer

    referrer是HTTP请求header的报文头,用于指明当前流量的来源参考页面。通过这个信息,我们可以知道访客是怎么来到当前页面的。这对于Web Analytics非常重要,可以用于分析不同渠道流量分布、用户搜索的关键词等。
    但是,这个字段同时会造成用户敏感信息泄漏(如:带有敏感信息的重置密码URL,若被Web Analytics收集,则存在密码被重置的危险)。

    Referrer Policy States

    新的Referrer规定了五种策略:

  • No Referrer:任何情况下都不发送Referrer信息

  • No Referrer When Downgrade:仅当协议降级(如HTTPS页面引入HTTP资源)时不发送Referrer信息。是大部分浏览器默认策略。

  • Origin Only:发送只包含host部分的referrer.

  • Origin When Cross-origin:仅在发生跨域访问时发送只包含host的Referer,同域下还是完整的。与Origin Only的区别是多判断了是否Cross-origin。协议、域名和端口都一致,浏览器才认为是同域。

  • Unsafe URL:全部都发送Referrer信息。最宽松最不安全的策略。

  1. Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline' 内容安全策略(CSP),其核心思想十分简单:网站通过发送一个 CSP 头部,来告诉浏览器什么是被授权执行的与什么是需要被禁止的。其被誉为专门为解决XSS攻击而生的神器。具体参考https://blog.csdn.net/u014465934/article/details/84199171

  2. X-Download-Options:noopen

    用于放置直接打开用户下载文件。

    X-Download-Options: noopen


  • noopen 用于指定IE 8以上版本的用户不打开文件而直接保存文件。在下载对话框中不显示“打开”选项。

  1. X-Permitted-Cross-Domain-Policies:none

    用于指定当不能将"crossdomain.xml"文件(当需要从别的域名中的某个文件中读取 Flash 内容时用于进行必要设置的策略文件)放置在网站根目录等场合时采取的替代策略。

    X-Permitted-Cross-Domain-Policies: master-only


  • master-only 只允许使用主策略文件(/crossdomain.xml)

如果你想修改这些Header的值,可使用如下配置:

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1      filter:        secure-headers:          xss-protection-header: 1;mode=block

上面的header对应的后缀:

  1. xss-protection-header

  2. strict-transport-security

  3. frame-options

  4. content-type-options

  5. referrer-policy

  6. content-security-policy

  7. download-options

  8. permitted-cross-domain-policies

如果想禁用某些Header,可使用如下配置:spring.cloud.gateway.filter.secure-headers.disable ,多个用 , 分隔。例如:

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1      filter:        secure-headers:          disable: frame-options,download-options
  • SetPath

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/{segment}filters:        #使用/{segment}来代替/user-center/{segment}后转发        - SetPath=/{segment}

如何进行第二代网关GateWay的搭建

用意跟之前差不多。

  • SetResponseHeader

在User项目中有这样一个Controller方法

@GetMapping("/addhead")public String addHeader(HttpServletRequest request, HttpServletResponse response) {
    response.addHeader("X-Response-Foo","Foo");    return "header";}
spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#将响应头X-Response-Foo的值更改为dee        - SetResponseHeader=X-Response-Foo,dee

如何进行第二代网关GateWay的搭建

  • SetStatus

修改响应的状态码,值可以是数字,也可以是字符串。但一定要是Spring HttpStatus 枚举类中的值。

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#修改返回状态码为401        - SetStatus=401

如何进行第二代网关GateWay的搭建

这里是可以正常返回结果的,只不过状态码被修改为401

  • StripPrefix

数字表示要截断的路径的数量。

  • Retry

针对不同的响应做重试,可配置如下参数:

  1. retries: 重试次数

  2. statuses: 需要重试的状态码,取值在 org.springframework.http.HttpStatus 中

  3. methods: 需要重试的请求方法,取值在 org.springframework.http.HttpMethod 中

  4. series: HTTP状态码系列,取值在 org.springframework.http.HttpStatus.Series 中

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#如果方法未找到,重试3次        - name: Retry          args:            retries: 3statuses: NOT_FOUND
  • RequestSize

为后端服务设置收到的最大请求包大小。如果请求大小超过设置的值,则返回 413 Payload Too Large 。默认值是5M
不过这里我设置了1字节,好像不起作用。

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#如果请求包超过1字节,返回413        - name: RequestSize          args:            maxSize: 1

经测试无效

  • Modify Request Body

可用于在Gateway将请求发送给后端微服务之前,修改请求体内容。该过滤器工厂目前处于BETA状态,不建议使用。

  • Modify Response Body

可用于修改响应体内容。该过滤器工厂目前处于BETA状态,不建议使用。

  • Default

如果你想为所有路由添加过滤器,可使用该属性。

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**      #该配置对所有的routes.id均有效      default-filters:      #跳转后省略第一个通配      - StripPrefix=1

自定义过滤器工厂

  • 过滤器生命周期

  1. pre: Gateway转发请求之前

  2. post: Gateway转发请求之后

  • 自定义过滤器工厂的方式

  1. 继承: AbstractGatewayFilterFactory

  2. 继承: AbstractNameValueGatewayFilterFactory

  • 核心API

  1. exchange.getRequest().mutate().xxx //修改request

  2. exchange.mutate().xxx //修改exchange

  3. chain.filter(exchange) //传递给下一个过滤器处理

  4. exchange.getResponse //拿到响应

  • 编写一个过滤器工厂

现在我们来写一个打印日志的过滤器工厂,该自定义过滤器工厂必须以GatewayFilterFactory结尾

@Slf4j@Componentpublic class PreLogGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Override    public GatewayFilter apply(NameValueConfig config) {return (((exchange, chain) -> {log.info("请求进来了...{},{}",config.getName(),config.getValue());            //获取请求            ServerHttpRequest modifiedRequest = exchange.getRequest()
                    .mutate()
                    .build();            //获取exchange            ServerWebExchange modifiedExchange = exchange.mutate()
                    .request(modifiedRequest)
                    .build();            //传递给下一个过滤器            return chain.filter(modifiedExchange);        }));    }
}

配置文件

spring:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848gateway:      routes:      - id: gateuri: lb://userpredicates:        #由/user-center来匹配跳转        - Path=/user-center/**filters:        #跳转后省略第一个通配        - StripPrefix=1#打印a,b日志        - PreLog=a,b

运行后,我们通过网关访问API后,打印日志如下

2019-12-20 14:09:48.066  INFO 2702 --- [ctor-http-nio-2] c.c.c.m.g.c.PreLogGatewayFilterFactory   : 请求进来了...a,b

全局过滤器

1 Combined Global Filter and GatewayFilter Ordering
2 Forward Routing Filter
3 LoadBalancerClient Filter
4 Netty Routing Filter
5 Netty Write Response Filter
6 RouteToRequestUrl Filter
7 Websocket Routing Filter
8 Gateway Metrics Filter
9 Marking An Exchange As Routed

  • Global Filter and GatewayFilter Ordering

当请求到来时,Filtering Web Handler 处理器会添加所有 GlobalFilter 实例和匹配的 GatewayFilter 实例到过滤器链中。

过滤器链会使用 org.springframework.core.Ordered 注解所指定的顺序,进行排序。Spring Cloud Gateway区分了过滤器逻辑执行的”pre”和”post”阶段,所以优先级高的过滤器将会在pre阶段最先执行,优先级最低的过滤器则在post阶段最后执行。数值越小越靠前执行。

@Slf4j@Configurationpublic class GlobleFilters {@Bean    @Order(-1)public GlobalFilter a() {return ((exchange, chain) -> {log.info("first pre filter");            return chain.filter(exchange).then(Mono.fromRunnable(
                    () -> log.info("third post filter")));        });    }@Bean    @Order(0)public GlobalFilter b() {return ((exchange, chain) -> {log.info("second pre filter");            return chain.filter(exchange).then(Mono.fromRunnable(
                    () -> log.info("second post filter")));        });    }@Bean    @Order(1)public GlobalFilter c() {return ((exchange, chain) -> {log.info("third pre filter");            return chain.filter(exchange).then(Mono.fromRunnable(
                    () -> log.info("first post filter")));        });    }
}

当有网关转发请求时

2019-12-20 15:03:34.263  INFO 3380 --- [ctor-http-nio-2] c.c.c.m.gateway.config.GlobleFilters     : first pre filter
2019-12-20 15:03:34.263  INFO 3380 --- [ctor-http-nio-2] c.c.c.m.gateway.config.GlobleFilters     : second pre filter
2019-12-20 15:03:34.263  INFO 3380 --- [ctor-http-nio-2] c.c.c.m.gateway.config.GlobleFilters     : third pre filter
2019-12-20 15:03:34.302  INFO 3380 --- [ctor-http-nio-7] c.c.c.m.gateway.config.GlobleFilters     : first post filter
2019-12-20 15:03:34.302  INFO 3380 --- [ctor-http-nio-7] c.c.c.m.gateway.config.GlobleFilters     : second post filter
2019-12-20 15:03:34.302  INFO 3380 --- [ctor-http-nio-7] c.c.c.m.gateway.config.GlobleFilters     : third post filter

  • Forward Routing Filter

整合Sentinel限流

Sentinel的版本必须在1.6及以上,我们这里为1.7

pom

<dependency>   <groupId>com.alibaba.csp</groupId>   <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId></dependency>

添加配置类

@Configurationpublic class GatewayConfig {private final List<ViewResolver> viewResolvers;    private final ServerCodecConfigurer serverCodecConfigurer;    public GatewayConfig(ObjectProvider<List<ViewResolver>> viewResolverProvider,                         ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolverProvider.getIfAvailable(Collections::emptyList);        this.serverCodecConfigurer = serverCodecConfigurer;    }@Bean    @Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {return new SentinelGatewayBlockExceptionHandler(viewResolvers,serverCodecConfigurer);    }@Bean    @Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter() {return new SentinelGatewayFilter();    }@PostConstruct    public void doInit() {
        initGatewayRules();    }/**     * 配置限流规则     */    private void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();        rules.add(new GatewayFlowRule("gate")
                    .setCount(1) //限流阈值                    .setIntervalSec(1)); //统计时间窗口,单位是秒,默认是1秒        GatewayRuleManager.loadRules(rules);    }
}

我们这里设置的为1秒钟只能通过一个请求。

如何进行第二代网关GateWay的搭建

如果我们在1秒钟内请求两次或以上,就会产生限流提示。

网关跨域设置

import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.cors.CorsConfiguration;import org.springframework.web.cors.reactive.CorsWebFilter;import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;import org.springframework.web.util.pattern.PathPatternParser;/** * 跨域配置 */@Configurationpublic class CrossDomainConfig {@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:  application:    name: gateway  cloud:    nacos:      discovery:        server-addr: xxx.xxx.xxx.xxx:8848gateway:      discovery:        locator:          enabled: true      # 跨域      globalcors:        corsConfigurations:          '[/**]':          allowedHeaders: "*"          allowedOrigins: "*"          allowedMethods:          - GET
            POST
            DELETE
            PUT
            OPTION

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI