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
目录
相关文章
|
8天前
|
小程序 数据可视化 Java
Java+后端Spring boot 开发的全套UWB定位方案,0.1米高精度定位系统源码
UWB定位系统由硬件定位设备、定位引擎和应用软件组成。该定位系统应用软件支持PC端和移动端访问,并提供位置实时显示、历史轨迹回放、人员考勤、电子围栏、行为分析、智能巡检等功能。定位精度高达10cm,同时具备高动态、高容量、低功耗的优点。应用场景包括:隧道、化工、工厂、煤矿、工地、电厂、养老、展馆、整车、机房、机场等。
32 8
|
1天前
|
负载均衡 Java API
Spring Cloud Gateway 详解:构建高效的API网关解决方案
Spring Cloud Gateway 详解:构建高效的API网关解决方案
5 0
|
4天前
|
Java 应用服务中间件 nginx
【Azure Spring Apps】Spring App部署上云遇见 502 Bad Gateway nginx
在部署Azure Spring App后,用户遇到502 Bad Gateway错误,问题源于Nginx。解决方案是检查并关闭Spring App的ingress-to-app TLS配置,因为若未启用HTTPS访问,Nginx通过HTTPS访问应用会导致此错误。
|
5天前
|
Java API 开发者
Java一分钟之-Spring Cloud Gateway:API网关
【6月更文挑战第10天】Spring Cloud Gateway是Spring Cloud生态中的API网关组件,基于Spring Framework 5、Reactor和Spring Boot 2.0,支持响应式编程。它提供路由转发、过滤器链(包括预处理、路由和后处理)和断言功能。快速入门涉及添加相关依赖和配置路由规则。常见问题包括路由冲突、过滤器顺序和性能瓶颈。通过动态路由和过滤器示例,展示了其灵活性。Spring Cloud Gateway是微服务架构的有力工具,可提升系统稳定性和开发效率。
111 0
|
9天前
|
监控 Java 数据库连接
Java一分钟之-Spring Boot:快速开发微服务
【6月更文挑战第7天】本文探讨了Spring Boot开发中的常见问题,包括起步依赖与版本管理、自动配置、启动类位置、日志配置、数据库连接、错误处理和Actuator监控。建议使用最新稳定版Spring Boot,通过`spring-boot-starter-parent`管理版本,理解自动配置原理,正确放置启动类,配置日志级别,准确设置数据库连接参数,自定义全局异常处理器,以及启用Actuator进行监控。不断学习和实践是应对各种问题的关键。
24 1
|
9天前
|
负载均衡 Java API
Spring GateWay
Spring GateWay
23 2
|
18天前
|
存储 JSON 前端开发
利用Spring MVC开发程序2
利用Spring MVC开发程序
22 1
|
18天前
|
设计模式 JSON 前端开发
利用Spring MVC开发程序1
利用Spring MVC开发程序
22 0
|
19天前
|
Cloud Native Java 开发者
Spring Boot 3.0-未来企业应用开发的基石
Spring Boot 3.0还支持其他云原生技术,如服务网格、配置中心等。这些技术的集成进一步提升了应用程序的可观测性、可配置性和可维护性,使得企业能够更好地管理和监控应用程序的运行状态。
26 0
|
22天前
|
Java Spring 容器
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
33 1
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入