Spring Cloud Gateway开发实战

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Spring Cloud Gateway开发实战

一、如何引入网关

要在您的项目中包括Spring Cloud Gateway,请使用group ID为org.springframework.Cloud和artifact ID 为Spring Cloud starter Gateway的启动器。有关使用当前Spring Cloud Release Train设置构建系统的详细信息,请参阅Spring Cloud Project页面。

如果包括启动器,但不希望启用网关,请设置 。spring.cloud.gateway.enabled=false

Spring Cloud Gateway 基于 Spring Boot 2.x、Spring WebFlux 和 Project Reactor 构建。 因此,当您使用 Spring Cloud Gateway 时,您知道的许多熟悉的同步库(例如 Spring 数据和 Spring 安全性)和模式可能不适用。 如果您不熟悉这些项目,我们建议您在使用Spring Cloud Gateway之前先阅读他们的文档以熟悉一些新概念。

Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。 它不适用于传统的 Servlet 容器或作为 WAR 构建时。

二、词汇表

  • Route:网关的基本构建基块。 它由 ID、目标 URI、谓词集合和筛选器集合定义。如果聚合谓词为 true,则匹配路由。
  • Predicate:这是一个Java 8函数谓词。输入类型是 Spring Framework ServerWebExchange。 这使您可以匹配 HTTP 请求中的任何内容,例如标头或参数。
  • Filter:这些是使用特定工厂构造的网关筛选器实例。 在这里,您可以在发送下游请求之前或之后修改请求和响应。

三、工作原理

下图提供了 Spring 云网关工作原理的高级概述:

客户端向 Spring Cloud 网关发出请求。如果网关处理程序映射确定请求与路由匹配,则会将其发送到网关 Web 处理程序。 此处理程序通过特定于请求的筛选器链运行请求。 筛选器用虚线划分的原因是筛选器可以在发送代理请求之前和之后运行逻辑。 执行所有“预”过滤器逻辑。然后发出代理请求。发出代理请求后,将运行“post”筛选器逻辑。

在没有端口的路由中定义的 URI 分别获取 HTTP 和 HTTPS URI 的默认端口值 80 和 443。

四、配置Route Predicate Factories and Gateway Filter Factories

有两种方法可以配置谓词和筛选器:快捷方式和完全展开的参数。下面的大多数示例都使用快捷方式。

名称和参数名称将作为代码列在每个部分的第一个或两个符号中。参数通常按快捷方式配置所需的顺序列出。

4.1. 快捷键配置

快捷方式配置由筛选器名称识别,后跟等号 (),后跟以逗号 () 分隔的参数值。=,

应用程序.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

前面的示例使用两个参数(cookie 名称和要匹配的值)定义路由谓词工厂。Cookiemycookiemycookievalue

4.2. 完全展开的参数

完全展开的参数看起来更像是具有名称/值对的标准 yaml 配置。通常,会有一个密钥和一个密钥。键是用于配置谓词或筛选器的键值对映射。nameargsargs

application.yml

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

这是上面显示的谓词的快捷方式配置的完整配置

五、开发指南

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

这些是编写网关的一些自定义组件的基本指南。

1、编写自定义路由谓词工厂

为了编写路由谓词,您需要实现RoutePredicateFactory。有一个抽象类叫做AbstractRoutePredicateFactory,您可以对其进行扩展。

MyRoutePredicateFactory.java

public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<HeaderRoutePredicateFactory.Config> {
    public MyRoutePredicateFactory() {
        super(Config.class);
    }
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        // grab configuration from Config object
        return exchange -> {
            //grab the request
            ServerHttpRequest request = exchange.getRequest();
            //take information from the request to see if it
            //matches configuration.
            return matches(config, request);
        };
    }
    public static class Config {
        //Put the configuration properties for your filter here
    }
}

2、编写自定义网关过滤器工厂

要编写GatewayFilter,您必须实现GatewayFilterFactory。您可以扩展一个名为AbstractGatewayFilterFactory的抽象类。以下示例显示了如何执行此操作:

例 76。PreGatewayFilterFactory.java

public class PreGatewayFilterFactory extends AbstractGatewayFilterFactory<PreGatewayFilterFactory.Config> {
    public PreGatewayFilterFactory() {
        super(Config.class);
    }
    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            //If you want to build a "pre" filter you need to manipulate the
            //request before calling chain.filter
            ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
            //use builder to manipulate the request
            return chain.filter(exchange.mutate().request(builder.build()).build());
        };
    }
    public static class Config {
        //Put the configuration properties for your filter here
    }
}

PostGatewayFilterFactory.java

public class PostGatewayFilterFactory extends AbstractGatewayFilterFactory<PostGatewayFilterFactory.Config> {
    public PostGatewayFilterFactory() {
        super(Config.class);
    }
    @Override
    public GatewayFilter apply(Config config) {
        // grab configuration from Config object
        return (exchange, chain) -> {
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                ServerHttpResponse response = exchange.getResponse();
                //Manipulate the response in some way
            }));
        };
    }
    public static class Config {
        //Put the configuration properties for your filter here
    }
}

DemogatewayApplication

package com.example.demogateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.ratelimit.RedisRateLimiter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class DemogatewayApplication {
    @RequestMapping("/circuitbreakerfallback")
    public String circuitbreakerfallback() {
        return "This is a fallback";
    }
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        //@formatter:off
        return builder.routes()
                .route("path_route", r -> r.path("/get")
                        .uri("http://httpbin.org"))
                .route("host_route", r -> r.host("*.myhost.org")
                        .uri("http://httpbin.org"))
                .route("rewrite_route", r -> r.host("*.rewrite.org")
                        .filters(f -> f.rewritePath("/foo/(?<segment>.*)",
                                "/${segment}"))
                        .uri("http://httpbin.org"))
                .route("circuitbreaker_route", r -> r.host("*.circuitbreaker.org")
                        .filters(f -> f.circuitBreaker(c -> c.setName("slowcmd")))
                                .uri("http://httpbin.org"))
                .route("circuitbreaker_fallback_route", r -> r.host("*.circuitbreakerfallback.org")
                        .filters(f -> f.circuitBreaker(c -> c.setName("slowcmd").setFallbackUri("forward:/circuitbreakerfallback")))
                                .uri("http://httpbin.org"))
                .route("limit_route", r -> r
                    .host("*.limited.org").and().path("/anything/**")
                        .filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
                    .uri("http://httpbin.org"))
                .route("websocket_route", r -> r.path("/echo")
                    .uri("ws://localhost:9000"))
                .build();
        //@formatter:on
    }
    @Bean
    RedisRateLimiter redisRateLimiter() {
        return new RedisRateLimiter(1, 2);
    }
    @Bean
    SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception {
        return http.httpBasic().and()
                .csrf().disable()
                .authorizeExchange()
                .pathMatchers("/anything/**").authenticated()
                .anyExchange().permitAll()
                .and()
                .build();
    }
    @Bean
    public MapReactiveUserDetailsService reactiveUserDetailsService() {
        UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build();
        return new MapReactiveUserDetailsService(user);
    }
    public static void main(String[] args) {
        SpringApplication.run(DemogatewayApplication.class, args);
    }
}

2.1、在配置中命名自定义过滤器和引用

自定义筛选器类名应以GatewayFilterFactory结尾。

例如,要在配置文件中引用名为Something的筛选器,该筛选器必须位于名为SomethingGatewayFilterFactory的类中。

可以创建不带后缀的网关筛选器,例如 。此筛选器可能是 如在配置文件中引用。这不是受支持的命名 约定和此语法可能会在将来的版本中删除。请更新过滤器 要合规的名称。GatewayFilterFactoryclass AnotherThingAnotherThing

3、编写自定义全局过滤器

若要编写自定义全局筛选器,必须实现GlobalFilter接口。这将筛选器应用于所有请求。

以下示例分别显示了如何设置全局前置过滤器和后置过滤器:

@Bean
public GlobalFilter customGlobalFilter() {
    return (exchange, chain) -> exchange.getPrincipal()
        .map(Principal::getName)
        .defaultIfEmpty("Default User")
        .map(userName -> {
          //adds header to proxied request
          exchange.getRequest().mutate().header("CUSTOM-REQUEST-HEADER", userName).build();
          return exchange;
        })
        .flatMap(chain::filter);
}
@Bean
public GlobalFilter customGlobalPostFilter() {
    return (exchange, chain) -> chain.filter(exchange)
        .then(Mono.just(exchange))
        .map(serverWebExchange -> {
          //adds header to response
          serverWebExchange.getResponse().getHeaders().set("CUSTOM-RESPONSE-HEADER",
              HttpStatus.OK.equals(serverWebExchange.getResponse().getStatusCode()) ? "It worked": "It did not work");
          return serverWebExchange;
        })
        .then();
}

六、故障排除

1、日志级别

以下记录器可能包有价值的故障排除信息:当日志设置为DEBUG和 TRACE

  • org.springframework.cloud.gateway
  • org.springframework.http.server.reactive
  • org.springframework.web.reactive
  • org.springframework.boot.autoconfigure.web
  • reactor.netty
  • redisratelimiter

2、监听

在 HttpClient and HttpServer模式下可以启用监听。当与将日志级别设置为 或 结合使用时,它可以记录信息,例如通过网络发送和接收的标头和正文。

要启用监听,请分别设置 :spring.cloud.gateway.httpserver.wiretap=true or spring.cloud.gateway.httpclient.wiretap=true 。


文章下方有交流学习区!一起学习进步!也可以前往官网,加入官方微信交流群你的支持和鼓励是我创作的动力❗❗❗

官网:Doker 多克; 官方旗舰店:首页-Doker 多克 多克创新科技企业店-淘宝网 全品优惠

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2天前
|
存储 Java Maven
Spring Boot WebFlux 增删改查完整实战 demo
Spring Boot WebFlux 增删改查完整实战 demo
|
2天前
|
监控 Java Sentinel
使用Sentinel进行服务调用的熔断和限流管理(SpringCloud2023实战)
Sentinel是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。
9 3
|
3天前
|
Java 开发者 Sentinel
Spring Cloud系列——使用Sentinel进行微服务保护
Spring Cloud系列——使用Sentinel进行微服务保护
16 5
|
7天前
|
Java 测试技术 持续交付
Java一分钟之-Spring Cloud Contract:契约测试
【6月更文挑战第16天】Spring Cloud Contract是微服务契约测试框架,通过DSL定义接口行为,使用WireMock生成存根进行独立开发验证。常见问题包括契约编写不清晰、未集成到CI/CD和契约版本控制混乱。例如,定义一个`GET /greeting`返回JSON响应的契约,Spring Cloud Contract会自动生成测试代码,帮助确保服务间接口一致性,提升开发效率和系统稳定性。
32 7
|
2天前
|
开发框架 移动开发 JavaScript
SpringCloud微服务实战——搭建企业级开发框架(四十七):【移动开发】整合uni-app搭建移动端快速开发框架-添加Axios并实现登录功能
在uni-app中,使用axios实现网络请求和登录功能涉及以下几个关键步骤: 1. **安装axios和axios-auth-refresh**: 在项目的`package.json`中添加axios和axios-auth-refresh依赖,可以通过HBuilderX的终端窗口运行`yarn add axios axios-auth-refresh`命令来安装。 2. **配置自定义常量**: 创建`project.config.js`文件,配置全局常量,如API基础URL、TenantId、APP_CLIENT_ID和APP_CLIENT_SECRET等。
|
3天前
|
安全 Java 数据安全/隐私保护
在Spring Cloud中实现单点登录(Single Sign-On, SSO)
在Spring Cloud中实现单点登录(Single Sign-On, SSO)
13 2
|
3天前
|
监控 Java Sentinel
Spring Cloud微服务架构
Spring Cloud微服务架构
16 1
|
8天前
|
Java 数据库 开发者
深入解析 Spring Cloud Seata:分布式事务的全面指南
深入解析 Spring Cloud Seata:分布式事务的全面指南
25 1
|
8天前
|
监控 Java API
深入解析 Spring Cloud Sentinel:分布式系统流量控制与熔断降级的全面指南
深入解析 Spring Cloud Sentinel:分布式系统流量控制与熔断降级的全面指南
17 0
深入解析 Spring Cloud Sentinel:分布式系统流量控制与熔断降级的全面指南
|
1天前
|
存储 数据可视化 关系型数据库

热门文章

最新文章