随笔 - 145  文章 - 0  评论 - 6  阅读 - 18万

Spring Cloud Gateway使用

代码示例

项目地址,见gateway-example

Spring Cloud Gateway官方文档

网关作用

网关可以为整个系统提供一个统一的入口,这样可以方便做一些统一的事情,比如统计流量、身份验证等。也方便客户端调用时不用记忆众多微服务的地址。

简单使用

引入依赖

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

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

网关最常用的作用就是把一个请求地址路由到真实的请求地址,Spring Cloud Gateway提供一个简单的配置,以服务名为前缀进行拦截路由。配置如下

server:
  port: 8084

spring:
  application:
    name: gateway-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    gateway:
      discovery:
        locator:
          enabled: true

其中 spring.cloud.gateway.discovery.locator.enabled=true将会开启以服务名为前缀的路由拦截。

目前网关的访问地址: http://127.0.0.1:8084

假设有另一个服务:nacos-producer,真实地址:127.0.0.1:8080

那么访问http://127.0.0.1:8084/nacos-producer/api/users/1这个路径,将被路由到下面这个地址

http://nacos-producer/api/users/1,而nacos-producer是一个服务名,在请求时将被ribbon替换成真实的ip和port,于是便变成了http://127.0.0.1:8080/api/users/1

路由断言工厂

Spring Cloud Gateway内置了很多路由断言工厂,具体可见官方文档,本节挑选PathRoutePredicateFactory作为使用例子,看名字就知道它是一个以路径做为匹配规则的路由断言工厂。

路由断言工厂的顶层接口为RoutePredicateFactory,抽象实现为AbstractRoutePredicateFactory。具体的实现一般都会继承AbstractRoutePredicateFactory类。

Spring Cloud Gateway的配置属性类为GatewayProperties,为路由断言工厂提供了两种配置方式,一种是传统的属性名字,另外一种是快捷方式(一行配置),下面就以PathRoutePredicateFactory为例。

实现的目标:

当请求路径以/api/users/开头,就路由到nacos-producer服务中

先看属性名方式:

@ConfigurationProperties(GatewayProperties.PREFIX)
@Validated
public class GatewayProperties {

	public static final String PREFIX = "spring.cloud.gateway";

    /**
     * 配置路由列表
     */
	private List<RouteDefinition> routes = new ArrayList<>();
    
    // ...略
}

@Validated
public class RouteDefinition {

	private String id;

    /**
     * 配置路由断言工厂
     */
	@NotEmpty
	@Valid
	private List<PredicateDefinition> predicates = new ArrayList<>();

	@Valid
	private List<FilterDefinition> filters = new ArrayList<>();

	@NotNull
	private URI uri;

	private Map<String, Object> metadata = new HashMap<>();

	private int order = 0;
    
    // ...略
}

public class PredicateDefinition {
    
	/**
	 * 路由断言工厂名称前缀
	 * PathRoutePredicateFactory: name=Path
	 * HeaderRoutePredicateFactory: name=Header
	 */
	@NotNull
	private String name;

    /**
     * 参数信息
     * map的key具体取决于路由断言工厂类中的Config类中的属性名
     * 如HeaderRoutePredicateFactory: key1=header  key2=regexp
     * 如PathRoutePredicateFactory: key1=patterns  key2=matchOptionalTrailingSeparator
     */
	private Map<String, String> args = new LinkedHashMap<>();
}
spring:
  application:
    name: gateway-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    gateway:
      routes:
          # 路由ID
        - id: nacos-producer-route
          # 路由到哪个地址,存在注册中心时可以使用服务名, lb://是使用负载均衡(LoadBalance)
          uri: lb://nacos-producer
          predicates:
              # 断言工厂:Path即使用PathRoutePredicateFactory工厂
            - name: Path
              args:
              	# List<String>:可使用[val1,val2]形式
                patterns: /api/users/**

再看快捷方式:

spring:
  application:
    name: gateway-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    gateway:
      routes:
      	  # 路由ID
        - id: nacos-producer-route
          # 路由到哪个地址,存在注册中心时可以使用服务名, lb://是使用负载均衡(LoadBalance)
          uri: lb://nacos-producer
          # 断言工厂:Path即使用PathRoutePredicateFactory工厂
          # =符号后面的是参数值,多个值用逗号分割
          predicates:
            - Path=/api/users/**

快捷方式绑定值规则逻辑

首先有一个前提,所有的路由断言工厂实现类名称全部以RoutePredicateFactory结尾,而名称的前缀部分则将作为使用哪个断言工厂的依据,这一点在上面的配置中已经体现,PathRoutePredicateFactory则为Path

然后看参数部分的绑定逻辑,每一个断言工厂都有一个Config类,用于保存参数信息。这里有一个很重要的接口,接口名为ShortcutConfigurable,主要解读这个类的作用就能明白绑定逻辑了。

我们的路由断言工厂顶层接口RoutePredicateFactory是继承了ShortcutConfigurable接口的

/**
 * 这个接口定义了两个重要的方法,如下所示,要想实现快捷方式配置,具体的路由断言工厂实现类
 * 都要重写这两个方法
 */
public interface ShortcutConfigurable {

    /**
     * 用于描述如何封装参数信息
     * 有3个值可选
     * DEFAULT、GATHER_LIST、GATHER_LIST_TAIL_FLAG
     */
	default ShortcutType shortcutType() {
		return ShortcutType.DEFAULT;
	}

    /**
     * 用于描述参数名字信息,有顺序的 
     */
	default List<String> shortcutFieldOrder() {
		return Collections.emptyList();
	}
    
    enum ShortcutType {
		
        /**
         * 默认行为, 将Map中的参数逐一映射
         */
		DEFAULT,

        /**
         * 将Map中的参数聚合成一个参数, 变成一个List, 赋值给shortcutFieldOrder方法
         * 第0一个元素指定的参数名
         */
		GATHER_LIST,

		/**
		 * 如果最后一个参数是boolean值,则将这个参数赋值给shortcutFieldOrder方法第1个
		 * 元素指定的参数名, 其它值聚合成一个List赋值给shortcutFieldOrder方法
         * 第0一个元素指定的参数名
		 */
		GATHER_LIST_TAIL_FLAG;
    
}

下面以具体例子来解释它们的区别

假设yaml中如下配置

XXX=name1,name2,true

例1

ShortcutType shortcutType() {
    return ShortcutType.DEFAULT;
}

default List<String> shortcutFieldOrder() {
    return [arg1, arg2, arg3]
}

class Config {
    // name1
    private String arg1;
    // name2
    private String arg2;
    // true
    private boolean arg3;
}

例2

ShortcutType shortcutType() {
    return ShortcutType.GATHER_LIST;
}

default List<String> shortcutFieldOrder() {
    return [args]
}

class Config {
    // [name1,name2,true]
    private List<String> args;
}

例3

ShortcutType shortcutType() {
    return ShortcutType.GATHER_LIST_TAIL_FLAG;
}

default List<String> shortcutFieldOrder() {
    return [args, flag]
}

class Config {
    // [name1,name2]
    private List<String> args;
    // true
    private boolean flag;
}

自定义路由断言工厂

本节将自定义一个PathPrefixRoutePredicateFactory路由断言工厂,即请求包含某个路径前缀则进行拦截。

注意事项

  • 名称必须以RoutePredicateFactory结尾
  • 继承AbstractRoutePredicateFactory
  • 实现shortcutTypeshortcutFieldOrder方法以便支持快捷方式配置
  • 实现apply方法来完成自定义逻辑的编写(即包含某一个前缀)
  • 注册到Spring容器中
package com.wangtao.gatewayexample.predicate;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.net.URI;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

public class PathPrefixRoutePredicateFactory extends AbstractRoutePredicateFactory<PathPrefixRoutePredicateFactory.Config> {

    private static final String ARG_KEY = "prefix";

    public PathPrefixRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList(ARG_KEY);
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
                URI uri = exchange.getRequest().getURI();
                return uri.getPath().startsWith(config.getPrefix());
            }
        };
    }

    @Validated
    public static class Config {

        private String prefix;

        public String getPrefix() {
            return prefix;
        }

        public void setPrefix(String prefix) {
            this.prefix = prefix;
        }
    }
}

配置使用

spring:
  application:
    name: gateway-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    gateway:
      routes:
       - id: nacos-producer-custom-route
         uri: lb://nacos-producer
         predicates:
           - PathPrefix=/api

或者

spring:
  application:
    name: gateway-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    gateway:
      routes:
       - id: nacos-producer-custom-route
         uri: lb://nacos-producer
         predicates:
           - name: PathPrefix
           	 args:
           	   prefix: /api
             

过滤器工厂

Spring Cloud Gateway中内置了许多的过滤器工厂(官网中例举了30个),当路由断言通过后,会执行该路由配置的一系列过滤器,这样我们可以修正或添加一些请求信息,比如增加参数,请求头等操作。其中配置方式与路由断言工厂一样,这里不再赘述。

过滤器工厂顶层接口为GatewayFilterFactory

本节将在请求头信息增加一个token,用于验证,将会用到AddRequestHeaderGatewayFilterFactory

spring:
  application:
    name: gateway-example
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

    gateway:
      routes:
       - id: nacos-producer-custom-route
         uri: lb://nacos-producer
         predicates:
           - PathPrefix=/api
         filters:
           - AddRequestHeader=customToken,waston

访问日志配置

通过JVM启动参数打开,不能通过application.yaml文件配置

-Dreactor.netty.http.server.accessLogEnabled=true

跨域配置

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;

/**
 * 全局跨域配置
 */
@Configuration
public class CorsConfig {

    @Bean
    public CorsWebFilter corsWebFilter() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        // 允许的请求头
        corsConfiguration.addAllowedHeader("*");
        // 允许的请求源 (如:http://localhost:8080)
        corsConfiguration.addAllowedOrigin("*");
        // 允许的请求方法 ==> GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
        corsConfiguration.addAllowedMethod("*");
        // URL 映射 (如: /admin/**)
        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
        return new CorsWebFilter(urlBasedCorsConfigurationSource);
    }
}
posted on   wastonl  阅读(279)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示