当前位置: 首页 > 图灵资讯 > 技术篇> gateway动态路由

gateway动态路由

来源:图灵教育
时间:2023-04-28 09:19:29

官网:Spring Cloud Gateway中文文档:Spring Cloud Gateway 2.1.0 中文官网文档 - 腾讯云开发者社区-腾讯云一,网关介绍:

gateway动态路由_服务器

gateway动态路由_服务器_02编辑

网关是目前微服务的统一入口。通常在微服务项目中,只有网关项目暴露在网络中,其他服务通常在内部网络中。用户访问网关,网关根据访问路径进行路由。 网关也是微服务的一部分,需要在Nacos注册项目,因为某个服务可能有多个服务器,所以也需要平衡负载依赖

案例:2.1.依赖项
<!--Gateway网关依赖于Gateway--><dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-gateway</artifactId></dependency><!--平衡依赖网关负荷--><dependency>  <groupId>org.springframework.cloud</groupId>  <artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!--Nacos依赖--><dependency>  <groupId>com.alibaba.cloud</groupId>  <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>

gateway动态路由_ide_03

2.2.实现路由的yml文件配置

实现路由的纯yml文件配置(包括Nacos注册和Gateway配置)

spring:  application:    name: gateway  cloud:    nacos:      discovery:        # 设置nacos服务器的地址        server-addr: localhost:8848        # 默认情况下,true是一个临时实例, 改为 false 是永久的例子        ephemeral: true    gateway:      #以下是Gateway路由配置的编写      routes:          #当前路由名称        - id: gateway-beijing          #匹配路由路径时,在Nacos注册的服务器中设置访问服务器,在那个项目中的spring.application.name设置)          #lb是loadbalancer负载平衡的缩写          uri: lb://beijing          #断言 在满足条件的时候做一些事情          predicates:              #当请求路径为//bj/开头时,将路由到上面设置的设置  lb://beijing  服务器            - Path=/bj/**        - id: gateway-shanghai          uri: lb://shanghai          predicates:            - Path=/sh/**

gateway动态路由_ide_04

编写配置类实现配置(这样,只能在配置文件中配置Nacos注册中心)

2.3.配置采用配置类

配置类配置,配置文件只需要写下边缘部分即可

spring:  application:    name: gateway  cloud:    nacos:      discovery:        # 设置nacos服务器的地址        server-addr: localhost:8848

gateway动态路由_spring_05

配置如下:

package cn.tedu.gateway.config;import org.springframework.cloud.gateway.route.RouteLocator;import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class GatewayConfiguration {    @Bean    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();        routes                //名为gateway-beijing的路由,匹配地址 /bj/** 使用  Nacos  里的 beijing 去处理请求 lb是负载平衡                .route("gateway-beijing", r -> r.path("/bj/**").uri("lb://beijing"))                .route("gateway-shanghai", r -> r.path("/sh/**").uri("lb://shanghai"))                            .route("gateway-after", r ->                    //匹配路径为 /show                    r.path("/show")                    //多个断言之间,用and方法连接                    .and()                    //断言时间,此时之后只能访问                    .after(ZonedDateTime.parse("2022-08-25T10:00:00+08:00[Asia/Shanghai]"))                    .and()                    ///断言查询参数,必须包含age,例如  /show?age=1                    .query("age")                    //设置过滤器并在过滤器中添加请求参数,实际控制器收到的请求如下: /show?age=1&name=tom                    .filters(f -> f.addRequestParameter("name", "tom"))                    ///使用shanghai处理请求                    .uri("lb://shanghai")                 )                //将路径为 /personal 要求,转移到石墨文档,石墨文件收到请求后,请求地址如下: https://shimo.im/personal                .route("gateway-shimo", r -> r.path("/personal").uri("https://shimo.im"))                .build();        return routes.build();    }    }

gateway动态路由_spring_06

2.4.动态路由添加到配置文件中:

动态路由(默认关闭)

开启方式:在配置文件中设置spring.cloud.gateway.discovery.locator.enabled=true

spring:  application:    name: gateway  cloud:    nacos:      discovery:        # 设置nacos服务器的地址        server-addr: localhost:8848        # 默认情况下,true是一个临时实例, 改为 false 是永久的例子        ephemeral: true    gateway:      discovery:        locator:          #打开动态路由          enabled: true

gateway动态路由_服务器_07

打开后,不需要在yacos中编写配置类或配置访问路由时,需要在Nacos中注册名称

假设Gateway网关的端口是9000北京服务器的端口是9001(Nacos注册为beijing),上海服务器的端口是9002(Nacos注册为shanghai)。 /xx/show 的接口

原访问地址:

http://localhost:9001/bj/showhttp://localhost:9002/sh/show

通过网关访问地址:

http://localhost:9000/beijing/bj/show >>等价于>> http://localhost:9001/bj/showhttp://localhost:9000/shanghai/sh/show >>等价于>> http://localhost:9002/sh/show

其中,地址中的 **shanghai/beijing **在Nacos中,注册服务器的名称将被路由到相应的服务器

注:可同时存在动态路由和手动设置配置文件或编写配置类别,同时生效

2.5.Knife4j测试网关模块:

使用swager/knife4j在网关中测试其他服务的接口,在pom文件中添加swager/knife4j依赖添加依赖

<dependency>  <groupId>com.github.xiaoymin</groupId>  <artifactId>knife4j-spring-boot-starter</artifactId></dependency>

gateway动态路由_ide_08

添加以下三类...添加后,访问 http://网关地址:网关端口/服务名称/doc.html 访问如下,其中 nacos-stock 注册到Nacos的服务名称

http://localhost:19000/nacos-stock/doc.html

控制器类:

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import reactor.core.publisher.Mono;import springfox.documentation.swagger.web.*;import java.util.Optional;@RestController@RequestMapping("/swagger-resources")public class SwaggerController {    @Autowired(required = false)    private SecurityConfiguration securityConfiguration;    @Autowired(required = false)    private UiConfiguration uiConfiguration;    private final SwaggerResourcesProvider swaggerResources;    @Autowired    public SwaggerController(SwaggerResourcesProvider swaggerResources) {        this.swaggerResources = swaggerResources;    }    @GetMapping("/configuration/security")    public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {        return Mono.just(new ResponseEntity<>(            Optional.ofNullable(securityConfiguration).orElse(            SecurityConfigurationBuilder.builder().build()),            HttpStatus.OK));    }    @GetMapping("/configuration/ui")    public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {        return Mono.just(new ResponseEntity<>(            Optional.ofNullable(uiConfiguration).orElse(            UiConfigurationBuilder.builder().build()),             HttpStatus.OK));    }    @GetMapping("")    public Mono<ResponseEntity> swaggerResources() {        return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));    }}

gateway动态路由_服务器_09

配置类

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.cloud.gateway.route.RouteLocator;import org.springframework.stereotype.Component;import springfox.documentation.swagger.web.SwaggerResource;import springfox.documentation.swagger.web.SwaggerResourcesProvider;import java.util.ArrayList;import java.util.HashSet;import java.util.List;import java.util.Set;@Componentpublic class SwaggerProvider implements SwaggerResourcesProvider {    /**     * 接口地址     */    public static final String API_URI = "/v2/api-docs";    /**     * 路由加载器     */    @Autowired    private RouteLocator routeLocator;    /**     * 网关应用名称     */    @Value("${spring.application.name}")    private String applicationName;    @Override    public List<SwaggerResource> get() {        ///接口资源列表        List<SwaggerResource> resources = new ArrayList<>();        //服务名称列表        List<String> routeHosts = new ArrayList<>();        // 获取所有可用的应用名称        routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null)                .filter(route -> !applicationName.equals(route.getUri().getHost()))                .subscribe(route -> routeHosts.add(route.getUri().getHost()));        // 去重,多负荷服务只添加一次        Set<String> existsServer = new HashSet<>();        routeHosts.forEach(host -> {            // 拼接url            String url = "/" + host + API_URI;            ///不存在就添加            if (!existsServer.contains(url)) {                existsServer.add(url);                SwaggerResource swaggerResource = new SwaggerResource();                swaggerResource.setUrl(url);                swaggerResource.setName(host);                resources.add(swaggerResource);            }        });        return resources;    }}

gateway动态路由_ide_10

过滤器类

import org.springframework.cloud.gateway.filter.GatewayFilter;import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.web.server.ServerWebExchange;@Componentpublic class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {    private static final String HEADER_NAME = "X-Forwarded-Prefix";    private static final String URI = "/v2/api-docs";    @Override    public GatewayFilter apply(Object config) {        return (exchange, chain) -> {            ServerHttpRequest request = exchange.getRequest();            String path = request.getURI().getPath();            if (!StringUtils.endsWithIgnoreCase(path,URI )) {                return chain.filter(exchange);            }            String basePath = path.substring(0, path.lastIndexOf(URI));            ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();            ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();            return chain.filter(newExchange);        };    }}

注意: 因为Spring Boot,Spring Cloud Gateway都有spring-boot-starter-web依赖,但前者使用Tomcat,后者使用Netty,会导致冲突,项目无法启动有三种解决方案

1. 在配置文件中,指定spring.main.web-application-type=reactive

spring:  main:    web-application-type: reactive

2. 添加spring-boot-starter-当web依赖时,排除Tomcattat

<!-- web实例 --><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId>  <exclusions>    <exclusion>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-tomcat</artifactId>    </exclusion>  </exclusions></dependency>

3.不添加springng-boot-starter-web依赖,只添加Spring Cloud 依赖Gateway

<!-- web实例 --><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-web</artifactId></dependency>