【动态路由】系统web url整合系列【springcloud-gateway实现】【不改hosts文件版】组件一:多个Eureka路由过滤器

Spring 4.2.0开发文档:核心概念与实战指南 Spring是一个开源的Java平台,最初由Rod Johnson创建,并首次发布于2003年。它为Java应用程序的开发提供了一个全面的编程和配置模型。Spring的核心特性包括依赖注入(DI)和面向切面编程(AOP),这使得它能够实现企业应用的解耦和模块化。Spring框架的模块化设计使其能够与其他多种框架无缝集成,并支持各种部署场景。 阅读详情

需求

      实现URL web资源整合,实现使用一个web地址访问多个web资源

方案

      本方案使用SpringCloud Gateway实现,不需要在hosts文件加添加域名映射(也不需要定义一系列域名),通过url路径来将请求转发到不同的Web资源

      如:http://${proxyIP}:${proxyPORT}/nacos1 

             转发到

             http://${nacos1IP}:${nacos1PORT}     

1、优点

  • 不需要用户端修改hosts文件(或是域名服务支持)

2、缺点

  • session信息可能会生产覆盖,存在session失效和横向越权风险

小知识:

        浏览器的session是按ip+端口(或域名+端口)作为唯一key存的

环境

spring-cloud 2024.0.0

spring-cloud gateway 4.2.0

实现代码

pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <!-- 3.4.0  3.3.6  3.1.5  3.0.12  -->
        <version>3.4.0</version>
        <!--  lookup parent from repository  -->
        <relativePath/>
    </parent>

    <groupId>person.daizd</groupId>
    <artifactId>gwproxy</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 统一管理jar包版本 -->
    <properties>
        <java.version>17</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>

        <!--   3.4.0   3.3.6  -->
        <spring-boot.version>3.4.0</spring-boot.version>
        <!-- 2024.0.0   2023.0.4    -->
        <spring-cloud.version>2024.0.0</spring-cloud.version>
        <!--  2023.0.3.2   2023.0.1.3    2022.0.0.0    2021.1   2021.0.6.1   2021.0.5.0   -->
        <spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version>

        <!--  springcloud 2020.02 以后需要单独引入     4.1.4   4.0.5  3.1.9  3.0.6  -->
        <spring-cloud-starter-bootstrap.version>4.1.4</spring-cloud-starter-bootstrap.version>
        <!-- 0.3.0-RC 适配springboot3    0.2.12 适配springboot2    0.1.10 适配springboot1   -->
        <nacos-config-spring-boot-starter.version>0.3.0-RC</nacos-config-spring-boot-starter.version>

        <!--        <junit.version>5.8.2</junit.version>-->
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.18.28</lombok.version>

        <commons-lang3.version>3.14.0</commons-lang3.version>
        <io.micrometer.version>1.9.17</io.micrometer.version>

        <!--  pmd-core 7.0.0:  3.25.0  3.24.0  3.23.0  3.22.0
              pmd-core 6.55.0:  3.21.2    3.13.0  3.11.0 copote  -->
        <maven-pmd-plugin.version>3.26.0</maven-pmd-plugin.version>
        <maven-clean-plugin.version>3.26.0</maven-clean-plugin.version>
        <fastjson2.version>2.0.53</fastjson2.version>
    </properties>

    <dependencies>
        <!--gateway的依赖 springcloud开发-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
            <version>${spring-cloud-starter-bootstrap.version}</version>
        </dependency>

        <!--   之前工程即没有引入 SpringCloud,也没有引入 SpringCloudAlibaba  -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>${spring-cloud-alibaba.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>${fastjson2.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${commons-lang3.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
        </dependency>

        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-resolver-dns-native-macos</artifactId>
            <version>4.1.115.Final</version>
            <classifier>osx-aarch_64</classifier>
        </dependency>


        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
<!--            <scope>test</scope>-->
        </dependency>

        <!-- 测试相关 这个包含junit5  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <dependencyManagement>
        <dependencies>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>

            <dependency>
                <groupId>io.micrometer</groupId>
                <artifactId>micrometer-registry-prometheus</artifactId>
                <version>${io.micrometer.version}</version>
                <scope>compile</scope>
            </dependency>

        </dependencies>

    </dependencyManagement>


    <build>

        <plugins>
            <!-- 用于支持热部署 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!-- 表示它将创建(fork)一个新的JVM来运行编译器。 spring boot plugin 3.0.0没有这个属性了
                    <fork>true</fork> -->
                    <addResources>true</addResources>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.1</version>

                <executions>
                    <execution>
                        <id>copy-resource</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/target</outputDirectory>
                            <resources>
                                <resource>
                                    <!-- 文件地址 -->
                                    <directory>${basedir}/src/main/resources</directory>
                                    <includes>
                                        <include>config.ini</include>
                                    </includes>
                                </resource>
                                <resource>
                                    <!-- 文件地址 -->
                                    <directory>${basedir}/src/main/resources</directory>
                                    <includes>
                                        <include>cookie.png</include>
                                    </includes>
                                </resource>
                            </resources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <target>${maven.compiler.target}</target>
                    <source>${maven.compiler.source}</source>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.3.1</version>
                <executions>
                    <execution>
                        <phase>verify</phase>
                        <goals>
                            <goal>jar-no-fork</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.3.2</version>
            </plugin>
            <!--  PMD toolkit  -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-pmd-plugin</artifactId>
                <version>3.26.0</version>
            </plugin>

            <!--- 支持单元测试 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.5.2</version>
            </plugin>
            <!--- 代码覆盖率工具 -->
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.8.12</version>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.7.1</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.4.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>person.daizd.GatewayApplication</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

配置

# 这里有很多组件:eureka、apollo、nacos、skywalking等,且每一类组件都有多套(如:有的各省一套)

# id与uri的映射
gwproxy.routes.cteureka_local=http://eureka:eureka@127.0.0.1:8200
gwproxy.routes.cmdb_local=http://127.0.0.1:8071

# eureka
gwproxy.routes.cteureka_sh_test=http://eureka:eureka@10.130.***.157:8200
gwproxy.routes.sxeureka_sh_test=http://eureka:eureka@10.130.***.157:8206
gwproxy.routes.fjeureka_sh_test=http://eureka:eureka@10.130.***.157:8207

gwproxy.routes.zjeureka_gcgz_nmb3_prod=http://10.141.***.240:20222

# apollo
gwproxy.routes.apollo_sh_test=http://10.130.***.157:28003
gwproxy.routes.apollo_sh_sit=http://10.130.***.112:30001

gwproxy.routes.ctapollo__nmb3_prod=http://10.141.***.240:20400
gwproxy.routes.lnapollo_idc01_nmb3_prod=http://10.141.***.240:20403

# sentinel
gwproxy.routes.lnsentinel_idc01_nmb3_prod=http://10.141.***.240:23903
gwproxy.routes.jssentinel_idc01_nmb3_prod=http://10.141.***.240:23915
gwproxy.routes.ahsentinel_idc01_nmb3_prod=http://10.141.***.240:23923

# apisix
# http://${gwproxy.root_uri}/apisix/index.html?app=apisix_sh_test
gwproxy.routes.apisix_sh_test=http://10.130.***.157:9000

gwproxy.routes.ctapisix_gz_gzb1_prod=http://10.***.5.131:32065

gwproxy.routes.ctapisix_idc01_nmb3_prod=http://10.141.***.240:31600
gwproxy.routes.lnapisix_idc01_nmb3_prod=http://10.141.***.240:31603


# prometheus 
# http://${gwproxy.root_uri}/prometheus_sh_test/graph
gwproxy.routes.prometheus_sh_test=http://10.130.***.136:9090
gwproxy.routes.prometheus_idc01_gzb1c1_prod=http://10.***.32.245:30006
gwproxy.routes.prometheus_idc01_gzb1c2_prod=http://10.***.32.246:30006
gwproxy.routes.prometheus_idc01_gzb1c3_prod=http://10.***.32.247:30006

gwproxy.routes.prometheus_idc01_nmb3c1_prod=http://10.141.***.240:30006
gwproxy.routes.prometheus_idc01_nmb3c2_prod=http://10.141.***.241:30006
gwproxy.routes.prometheus_idc01_nmb3c3_prod=http://10.141.***.242:30006

gwproxy.routes.prometheus_sh_crm120=http://10.130.***.120:9090
gwproxy.routes.prometheus_sh_crm121=http://10.130.***.121:9090
gwproxy.routes.prometheus_gz_saas190=http://10.***.31.190:30900

# nacos
# http://${gwproxy.root_uri}/nacos_sh_test/nacos/#/login
gwproxy.routes.nacos_sh_test=http://10.130.***.92:18848

# gateway
gwproxy.routes.ahgateway_idc01_nmb3_prod=http://10.141.***.242:23266
gwproxy.routes.jsgateway_idc01_nmb3_prod=http://10.141.***.216:32015
gwproxy.routes.bjgateway_idc01_nmb3_prod=http://10.141.***.209:32008
gwproxy.routes.lngateway_idc01_nmb3_prod=http://10.141.***.204:30003

# elasticsearch
gwproxy.routes.elasticsearch_gz_247=http://10.***.6.247:9200

# kibana     待优化KibanaRoute1 用于同时支持kibana 直接访问和代理访问,不过官方说只能2选一,优化难度大
# /kibana_local/login?next=/kibana_local/
gwproxy.routes.kibana_local=http://esserver:5601

# /kibana_sh_test/login?next=/kibana_sh_test/
gwproxy.routes.kibana_sh_cs134_test=http://10.130.***.134:15601
gwproxy.routes.kibana_sh_jg92_test=http://10.130.***.92:5602

# /gzkibana_5601/login?next=/gzkibana_5601/
# /gzkibana_5601/login?msg=LOGGED_OUT
gwproxy.routes.kibana_gz_5601_prod=http://10.***.6.247:5601
gwproxy.routes.kibana_gz_5602_prod=http://10.***.6.247:5602
gwproxy.routes.kibana_gz_5603_prod=http://10.***.6.247:5603

# /nmkibana_5601/login?next=%2F
gwproxy.routes.kibana_nm_5601_prod=http://10.141.137.***:5601
gwproxy.routes.kibana_nm_5602_prod=http://10.141.137.***:5601
gwproxy.routes.kibana_nm_5603_prod=http://10.141.137.***:5601

# timetask  当前可参考kibana 通过改根路径解决(这里直接改应用包名)
# http://${gwproxy.root_uri}/timetask/toLogin
# http://${gwproxy.root_uri}/cttimetask_idc01_nmb3_prod/timetask/toLogin
# 因静态资源命名冲突,所以两种(改工程名与直接支持)配置不能同时存在
#
gwproxy.routes.timetask=http://10.141.***.240:22400
#gwproxy.routes.timetask-xxl-job=http://10.141.***.240:22400
gwproxy.routes.cttimetask_idc01_nmb3_prod=http://10.141.***.240:22400
gwproxy.routes.cttimetask_idc01_gzb1_prod=http://10.***.5.131:22400

# Grafana
# http://${gwproxy.root_uri}/grafana_sh_prod/login
gwproxy.routes.grafana_sh_prod=http://10.130.***.121:50001

# Ambari (Hadoop - Hbase )   
# http://${gwproxy.root_uri}/ambari_sh_prod/#/login
gwproxy.routes.ambari_sh_prod=http://10.***.6.231:8080

# kafka-map   
gwproxy.routes.kafkamap_sh_jg92_test=http://10.130.***.92:8083
gwproxy.routes.kafkamap_sh_prod=http://10.130.***.121:8093

# cmak
# /cmak_sh_jg93_test
gwproxy.routes.cmak_sh_jg93_test=http://10.130.***.93:8094
# 没启或没安装
gwproxy.routes.cmak_sh_prod=http://10.130.***.121:8094

# skywalking
gwproxy.routes.skywalking_sh_jg131_test=http://10.130.***.131:30198
# 
gwproxy.routes.skywalking_xw_nm_prod=http://10.141.***.41:31051
gwproxy.routes.skywalking_xw_gz_prod=hhttp://10.***.6.204:31051
gwproxy.routes.skywalking_idc01_nmb3_prod=hhttp://10.141.***.240:31051

# pinpoint
gwproxy.routes.pinpoint_idc01_gzb1_prod=http://10.***.5.131:20900
gwproxy.routes.pinpoint_idc01_nmb3_prod=http://10.141.***.95:20900

# redmine
gwproxy.routes.redmine_idc01_nmb3_prod=http://10.142.***.247:8080

# harbor
gwproxy.routes.harbor_idc01_gzb1_prod=http://10.***.100.18:8021

# jenkins
gwproxy.routes.jenkins_sh_cs124_prod=http://10.130.***.124:1906

# nexus
gwproxy.routes.nexus_sh_jg122_prod=http://10.130.***.122:18081

# gitlab
gwproxy.routes.gitlab_sh_jg122_prod=http://10.130.***.122:8082


# kubesphere
gwproxy.routes.kubesphere_sh_cs131_prod=http://10.130.***.131:30880


# nightingale 
# nightingale_sh_test/login   
# nightingale_sh_test/metric/explorer
# 10.130.***.120 nightingale.sh.test
# 10.130.***.120 nightingale.sh.prod
gwproxy.routes.nightingale_sh_test=http://10.130.***.136:17000
gwproxy.routes.nightingale_sh_prod=http://10.130.***.121:17000

# ~~~~~~~~~~~~~~~~   业务应用 begin   ~~~~~~~~~~~~~~~~~~~
# http://${gwproxy.root_uri}/portal1_sh_prod/login
gwproxy.routes.portal1_sh_prod=http://10.130.***.121:8082


gwproxy.routes.web2_sh_test=http://10.130.***.124:8201
# http://${gwproxy.root_uri}/web2_idc01_nmb3_prod/web2/
gwproxy.routes.web2_idc01_nmb3_prod=http://10.***.228.140:32100

配置类

/**
 * @Description: 从nacos获取配置
 * @Author: dand
 * @CreateDate: 2024/12/14 5:43 PM
 * @Version: 1.0
 */

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
@ConfigurationProperties(prefix = "gwproxy")
@Getter
@Setter
@RefreshScope
public class NacosMappingConfig {

    private Map<String, String> routes;

}

动态路由实现【重点】

# 这里涉及很多组件,本文先上eureka的代码(其他组件支持代码读者可自行注释掉),后续更新文章其他组件相关动态路由实现代码会陆续上架

package person.daizd.config;

import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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;
import person.daizd.config.route.*;
import person.daizd.filters.factory.*;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/***
 * @Author dand   QQ:413881461
 * @Slogan 致敬大师,致敬未来的你
 */
@Slf4j
@Configuration
public class GatewayConfig {

    @Value("${gwproxy.root_uri}")
    private String rootUri;

    @Autowired
    private NacosMappingConfig nacosMappingConfig;

    @Autowired
    private CmdbFilterFactory1 cmdbFilterFactory1;
    @Autowired
    private CmdbFilterFactory2 cmdbFilterFactory2;

    @Autowired
    private ApisixFilterFactory1 apisixFilterFactory1;
    @Autowired
    private ApisixFilterFactory2 apisixFilterFactory2;

    @Autowired
    private EurekaFilterFactory1 eurekaFilterFactory1;
    @Autowired
    private EurekaFilterFactory2 eurekaFilterFactory2;

    @Autowired
    private N9eFilterFactory1 n9eFilterFactory1;
    @Autowired
    private N9eFilterFactory2 n9eFilterFactory2;

//    @Autowired
//    private KibanaFilterFactory1 kibanaFilterFactory1;
//    @Autowired
//    private KibanaFilterFactory2 kibanaFilterFactory2;

    @Autowired
    private TimeTaskFilterFactory1 timeTaskFilterFactory1;
    @Autowired
    private TimeTaskFilterFactory2 timeTaskFilterFactory2;

    @Bean
//    @RefreshScope
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) throws NacosException {

        log.debug("nacosMappingConfig:{}",nacosMappingConfig.getRoutes());

        // 需要换成配置中取
//        Map<String,String> map = new HashMap<String,String>();
        Map<String,String> map = nacosMappingConfig.getRoutes();
//        map.put("cteureka_local","http://eureka:eureka@127.0.0.1:8200");
//        map.put("cmdb_local","http://127.0.0.1:8071");

        RouteLocatorBuilder.Builder innerBuilder = builder.routes();

        Set<Map.Entry<String, String>> set = map.entrySet();
        Iterator<Map.Entry<String, String>> it = set.iterator();

        /**
         *  特别注意:
         *  1、路径名称不能与已有资源名重命
         *  2、相互之间不能是包含(子集)关系
         *
         *
         */
        // 先统一处理所有eureka
        while (it.hasNext()) {
            Map.Entry<String, String> entry = it.next();

            if(entry.getKey().contains("eureka")){
                innerBuilder = EurekaRoute.route(eurekaFilterFactory1, eurekaFilterFactory2,
                          innerBuilder,    entry,  rootUri);
            }
            // 防止不重复处理 用 else if
            else if(entry.getKey().contains("cmdb")){
                innerBuilder = CmdbRoute.route(cmdbFilterFactory1, cmdbFilterFactory2,
                        innerBuilder,    entry,  rootUri);
            }
            else if(entry.getKey().contains("sentinel")){
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            else if(entry.getKey().contains("apisix")){
                innerBuilder = ApisixRoute2.route(apisixFilterFactory1,apisixFilterFactory2,
                        innerBuilder,    entry,  rootUri);
            }
            else if(entry.getKey().contains("ddal")){
                innerBuilder = CmdbRoute.route(cmdbFilterFactory1, cmdbFilterFactory2,
                        innerBuilder,    entry,  rootUri);
            }
            /* 待优化KibanaRoute1 用于同时支持kibana 直接访问和代理访问,不过官方说只能2选一,优化难度大
               另外也可开通SSO能力后研究其他方案
               前端使用了react,采用nodejs部署
             */
            else if(entry.getKey().contains("kibana")){
                innerBuilder = KibanaRoute2.route(
                        innerBuilder,    entry,  rootUri);
            }
            else if(entry.getKey().contains("elasticsearch")){
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            else if(entry.getKey().contains("nacos")){
                innerBuilder = CmdbRoute.route(cmdbFilterFactory1, cmdbFilterFactory2,
                        innerBuilder,    entry,  rootUri);
            }
            else if(entry.getKey().contains("prometheus")){
                innerBuilder = CmdbRoute.route( cmdbFilterFactory1, cmdbFilterFactory2,
                        innerBuilder,    entry,  rootUri);
            }
            // @todo  n9e 前端使用了React和D3.js, 等官方支持修改根路径(改为与配置名一致)或 二次n9e前端工程(https://github.com/n9e/fe)
            else if(entry.getKey().contains("nightingale")){
                innerBuilder = N9eRoute.route(    n9eFilterFactory1, n9eFilterFactory2,
                        innerBuilder,    entry,  rootUri);
            }
            /*
             * 方案一: 改timetask 上下文(应用名/根路径)-- 推荐(kibana 方案)
             * 方案二: 直接支持(不调整应用) -- 目前与n9e一样存在类似(菜单路径)问题
             */
            else if(entry.getKey().contains("timetask")){
                innerBuilder = KibanaRoute2.route(
                        innerBuilder,    entry,  rootUri);

//                innerBuilder = TimeTaskRoute.route( timeTaskFilterFactory1, timeTaskFilterFactory2,
//                        innerBuilder,    entry,  rootUri);
            }
            // @todo
            else if(entry.getKey().contains("grafana")){  // /grafana_sh_prod/login
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            else if(entry.getKey().contains("ambari")){  // /ambari_sh_prod/#/login
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // eureka √
            else if(entry.getKey().contains("kafkamap")){  // /kafkamap_sh_jg92_test/#/login
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // cmak 存在类似n9e的菜单路径问题
            else if(entry.getKey().contains("cmak")){  // /cmak_sh_jg93_test
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 补充了一个js待验证
            else if(entry.getKey().contains("skywalking")){  // /skywalking_sh_jg131_test/General-Service/Services
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 初步让为 √
            else if(entry.getKey().contains("pinpoint")){  // /pinpoint_gcgz_gzb1_prod/#/main
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 120网络不通
            else if(entry.getKey().contains("redmine")){  // /redmine_gcgz_nmb3_prod/login
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 初步让为harbor上下文路径可以修改
            else if(entry.getKey().contains("harbor")){  // /harbor_gcgz_gzb1_prod/harbor/sign-in
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 能登陆,但主页面显示不正常
            else if(entry.getKey().contains("jenkins")){  // /jenkins_sh_cs124_prod/jenkins/login
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 登陆有问题
            else if(entry.getKey().contains("nexus")){  // /nexus_sh_jg122_prod/nexus/#welcome
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 静态资源访问有问题
            else if(entry.getKey().contains("gitlab")){  // /gitlab_sh_jg122_prod/users/sign_in
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 未知错误
            else if(entry.getKey().contains("kubesphere")){  // /kubesphere_sh_cs131_prod/login
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
            // 可以登陆,静态资源加载有问题
            else if(entry.getKey().contains("opsportal")){  // /opsportal_sh_prod/login
                innerBuilder = CommonRoute.route(
                        innerBuilder,    entry,  rootUri);
            }
        };

        return innerBuilder.build();
    }

}

eureka动态路由实现类

package person.daizd.config.route;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.cloud.gateway.route.builder.GatewayFilterSpec;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.cloud.gateway.route.builder.UriSpec;
import person.daizd.filters.factory.*;

import java.util.Map;
import java.util.function.Function;

/**
 * 路由
 *
 * @Author: daizd
 * @CreateDate: 2024/12/13 9:28 PM
 * @Version: 1.0
 */
@Slf4j
public class EurekaRoute {
    public static RouteLocatorBuilder.Builder route(EurekaFilterFactory1 filterFactory1,
                                                    EurekaFilterFactory2 filterFactory2,
                                                    RouteLocatorBuilder.Builder innerBuilder,
                                                    Map.Entry<String, String> entry,
                                                    String rootUri
    ){
        // 每个eureka要配两个路由, 第一个
        innerBuilder = innerBuilder.route( entry.getKey()+"_1", // id
                r -> r.path("/"+entry.getKey()+"/**")       //   --   /cteureka/**
                        .filters( f -> f.stripPrefix(1)
                                .preserveHostHeader()
                                .saveSession()  )

                        .uri( entry.getValue() ));


        log.debug("Referer:"+rootUri+"/"+entry.getKey()+"[^\\s]*" );
        log.debug("uri:"+entry.getValue() );
        // 每个eureka要配两个路由,第二个  modifyRedirectFilterFactory
        innerBuilder.route( entry.getKey()+"_2", // id
                r -> r.header("Referer",rootUri+"/"+entry.getKey()+"[^\\s]*" )
//                        .filters( f -> f.stripPrefix(0).preserveHostHeader() )
                        .filters(new Function<GatewayFilterSpec, UriSpec>() {
                            @Override
                            public UriSpec apply(GatewayFilterSpec gatewayFilterSpec) {
                                return gatewayFilterSpec.filter(
                                        filterFactory2.apply(applyFilter("app",entry.getKey() ))
                                );
                            }
                        })
                        .uri( entry.getValue() ));
        return innerBuilder;
    }

    /**
     * 构造config
     *
     * @param headerName
     * @param headerValue
     * @return NameValueConfig
     */
    private static AbstractNameValueGatewayFilterFactory.NameValueConfig applyFilter(String headerName, String headerValue) {
        AbstractNameValueGatewayFilterFactory.NameValueConfig config = new AbstractNameValueGatewayFilterFactory.NameValueConfig();
        config.setName(headerName);
        config.setValue(headerValue);
        return config;
    }
}

GatewayFilterFactory1【保留】

package person.daizd.filters.factory;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * 用在路由1上
 *
 * @Author: dand
 * @CreateDate: 2024/12/8 7:49 PM
 * @Version: 1.0
 *
 *  没有用到
 */
@Component
@Slf4j
public class EurekaFilterFactory1 extends AbstractNameValueGatewayFilterFactory  {

    @Value("${gwproxy.root_uri}")
    private String rootUri;

    /**
     * 1、如果是重定向则定向到配置参数(应用名)对应的路径
     * 2、如果不是重定向,且第一级路径与应用名不一致,则修改为一致
     *
     * @param config
     * @return
     */
    @Override
    public GatewayFilter apply( NameValueConfig config) {
        return (exchange, chain) ->
                chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    ServerHttpRequest request = exchange.getRequest();
                    ServerHttpResponse response = exchange.getResponse();
                    HttpStatusCode statusCode = response.getStatusCode();

                    String name = config.getName();
                    String value = config.getValue();
                    String rootUrl = rootUri+"/"+config.getValue();
                    if (statusCode == HttpStatus.SEE_OTHER || statusCode == HttpStatus.FOUND) {
                        String location = response.getHeaders().getFirst(HttpHeaders.LOCATION);
                        // 修改location的逻辑
                        if(response.getHeaders().containsKey("Set-Cookie")
//                                || request.getHeaders().containsKey("Cookie")
                        ){
                            // 有 Set-Cookie  和 cookie都认为已登陆
                            response.getHeaders().set(HttpHeaders.LOCATION, rootUrl );
                            log.info("response.getHeaders().containsKey(\"Set-Cookie\") , to rootUrl:{} ",rootUrl);
                        }else{
                            response.getHeaders().set(HttpHeaders.LOCATION, rootUrl+"/signin" );
                            log.info(" else : {}/signin ",rootUrl);
                        }
                    }
                }));
    }

    @Override
    public Class<NameValueConfig> getConfigClass() {
        // 如果你有配置属性,返回配置属性的类;如果没有,返回null
        return NameValueConfig.class; // 或者 return YourConfigProperties.class;
    }
}

GatewayFilterFactory2

package person.daizd.filters.factory;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;

/**
 * 用在路由2上
 *
 * @Author: dand
 * @CreateDate: 2024/12/8 7:49 PM
 * @Version: 1.0
 */
@Component
@Slf4j
public class EurekaFilterFactory2 extends AbstractNameValueGatewayFilterFactory  {

    @Value("${gwproxy.root_uri}")
    private String rootUri;

    /**
     * 1、如果是重定向则定向到配置参数(应用名)对应的路径
     * 2、如果不是重定向,且第一级路径与应用名不一致,则修改为一致
     *
     * @param config
     * @return
     */
    @Override
    public GatewayFilter apply( NameValueConfig config) {
        return (exchange, chain) ->
                chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    ServerHttpResponse response = exchange.getResponse();
                    HttpStatusCode statusCode = response.getStatusCode();

                    String remoteIp = exchange.getRequest().getRemoteAddress().getHostName();
                    log.info("remoteIp:"+remoteIp);

                    // "http://127.0.0.1:8089/oldcmdb";
                    String rootUrl = rootUri+"/"+config.getValue();
                    System.out.println("statusCode:"+statusCode);
//                    FluxOnAssembly a;
                    if (statusCode != HttpStatus.SEE_OTHER && statusCode != HttpStatus.FOUND) {

                        ServerHttpRequest request = exchange.getRequest();
                        URI uri = request.getURI() ;
                        String path = request.getPath().value();

                        HttpHeaders headers = request.getHeaders();
                        List<String> referer = headers.get("referer");
                        log.info("path:{}", uri.getPath() );
                        if( referer!=null
                                && referer.size()>0
                                && referer.get(0).indexOf( rootUrl ) != -1 // referer 包含:http://127.0.0.1:8089/oldcmdb
                                && uri.getPath().indexOf( "/"+config.getValue() ) == -1  // uri 不包含 /oldcmdb
                                && (uri.getPath().equalsIgnoreCase("/")
                                   || uri.getPath().equalsIgnoreCase("/lastn")   )
                                  ) //  是html页面
                        {
                            // 重定向到 RewritePath=/(?<segment>.*), /oldcmdb/$\{segment}
                            exchange.getResponse().setStatusCode(HttpStatus.FOUND);
                            exchange.getResponse().getHeaders().setLocation( URI.create( "/"+config.getValue()+ path) );
                            log.info("uri.getPath().indexOf( \".html\") ");
                        }
                    }
                }));
    }

    @Override
    public Class<NameValueConfig> getConfigClass() {
        // 如果你有配置属性,返回配置属性的类;如果没有,返回null
        return NameValueConfig.class; // 或者 return YourConfigProperties.class;
    }
}

效果说明

为了让读者更好的读懂上面的代码,下面给出静态配置实现(上面代码动态实现了该效果且更灵活)

server:
  port: 8089

gwproxy:
  root_uri: ${root_uri:http://127.0.0.1:8089}

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      httpclient:
        response-timeout: PT60S
        connect-timeout: 2000
        # 链接池配置
        pool:
          # 最大连接数
          max-connections: 10000
          # 仅对于FIXED类型,等待获取线程的最长时间(毫秒)
          acquire-timeout: 1000
          # 最大空闲时间
          max-idle-time: PT10S
          # 设置固定链接池
          type: fixed
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true


      #路由规则
      routes:

        #  ~~~~~~~~  eureka  ~~~~~~~~~~~~~~~~
        - id: cteureka_route_1 #  8100000    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://eureka:eureka@127.0.0.1:8200          #匹配后提供服务的路由地址
          predicates:
          - Path=/cteureka/**         # 断言,路径相匹配的进行路由
          filters:
          - StripPrefix=1  # 转发之前去掉第一层路径

        - id: cteureka_route_2
          uri: http://eureka:eureka@127.0.0.1:8200          #匹配后提供服务的路由地址
          predicates:
            - Header=Referer,${gwproxy.root_uri}/cteureka


management:
  info: # 显示任意的应用信息,默认关闭  springBoot版本:2.7.15  GA如果是<2.7.5 的版本默认是开启的
    env:
      enabled: true
  endpoints:
    web:
      exposure:
        include: "*"
      base-path: /whoami
info:
  app:
    name: gateway
    encoding: "@project.build.sourceEncoding@"
    java:
      source: "@java.version@"
      target: "@java.version@"
  company:
    name: www.asiainfo.com

debug: true

附件一:整合界面地址效果截图

附件二:Spring Cloud Gateway官方文档

Spring Cloud Gateway 帮助文档

Spring Cloud Gateway 官方首页

附件三:Spring Cloud Gateway介绍

在Spring Cloud Gateway中,Spring Cloud Gateway是基于Spring Framework 5.0和Project Reactor等技术构建的API网关。它旨在为微服务架构提供一种简单有效的方式来路由到APIs,并提供跨多个服务和应用程序的请求路由、负载均衡、路径重写、动态路由、监控、安全等功能。Spring Cloud Gateway旨在提供一种简单而有效的方法来路由到微服务架构中的APIs,并具有以下主要特性:

  1. 基于Spring WebFlux的反应式编程模型:Spring Cloud Gateway利用了Spring WebFlux的非阻塞特性,能够高效地处理大量并发请求。

  2. 动态路由:支持基于配置中心的动态路由配置,可以实时更改路由规则,无需重新启动服务。

  3. 负载均衡:内置了Spring Cloud LoadBalancer的支持,可以轻松实现服务之间的负载均衡。

  4. 路径重写和过滤:支持请求路径的修改和基于请求内容的过滤,例如请求参数的修改、响应内容的修改等。

  5. 安全:集成了Spring Security,支持OAuth2.0等安全协议,可以轻松实现API的安全认证和授权。

  6. 监控:通过集成Actuator和Micrometer等工具,可以方便地监控网关的运行状态和性能指标。

核心概念

  • Route:路由是网关的基本构建单元,它定义了如何将请求转发到特定的目标服务。

  • Predicate:断言是决定一个路由是否匹配的逻辑。例如,可以根据请求的路径、主机名、HTTP方法等来定义断言。

  • Filter:过滤器可以在请求被路由到目标服务之前或之后执行逻辑。例如,可以在请求到达之前添加认证信息,或在响应返回之前添加日志信息。

示例配置

以下是一个简单的Spring Cloud Gateway配置示例,用于定义一个路由:

spring:
  cloud:
    gateway:
      routes:
        - id: my_route
          uri: http://example.com
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*), /$\{segment}

这个配置定义了一个ID为my_route的路由,它将所有路径以/api/开头的请求转发到http://example.com。同时,使用了一个过滤器RewritePath来重写请求路径。

总结

Spring Cloud Gateway是一个功能丰富、高性能的API网关解决方案,非常适合作为微服务架构中的统一入口点。通过使用Spring Cloud Gateway,开发者可以轻松实现API的路由、负载均衡、安全认证等功能,从而构建出更加健壮和可扩展的微服务系统。

40-Type-C电路设计 Type-C电路设计 阅读详情

相关推荐

线性代数学习笔记(十)——矩阵运算(二)

本篇笔记讲解矩阵的幂运算和矩阵的转置,其中矩阵进行幂运算的前提是矩阵为方阵,矩阵幂运算的两条性质与数的幂运算规则类似;矩阵转置的定义与行列式转置类似,但要注意由于矩阵的行数和列数不同,所以转置之后行数和列数变换。

li2008kui的专栏 1万+

springboot3.x集成nacos 并实现多环境配置

​ springboot3.0.x 和springboot3.1.x 可直接使用nacos-config-spring-boot-starter 包。 springboot >=3.2.x 需要使用spring-cloud-starter-alibaba-nacos-config包,因为常规包在我发布该文时nacos官方还没更新,已更新的版本只支持到3.1.x,cloud的包2024年4月份进行了更新,可以支持3.2.x及以上版本。

记录点滴 3万+

TestFlight分发测试app,提示无法安装 所请求的App不可用或者不存在

TestFlight分发测试app,提示无法安装 所请求的App不可用或者不存在

天穹云原生 9170

nacos注册中心和配置中心

nacos 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。nacos官方文档:https://nacos.io/zh-cn/相关概念:https://nacos.io/zh-cn/docs/architecture.htmlnacos是AP架构,注重可用性和分区容错性,java语言,集群架构的话通过nginx做负载均衡,然后节点之间互相同步数据本文演示在springcloud中使用nacoshttps://github.com/alibaba/spring-cloud-alibaba/wi

我的技术博客 1712

【OTDR曲线工具箱】04 批量生成sor文件

软件下载地址:http://120.78.150.214:9999/isora.zip 通过一个测试数据sor文件,批量生成多个测试文件(基于Bellcore GR196及SR-4731标准)。主要考虑哪些问题: 1、sor测试是否符合要求(主要是衰减系数) 2、多个文件的创建时间 3、文件必须随机处理,不要看省去一模一样。 来说说怎么操作的 第一步:选择参考曲线 参考曲线的选择由两种方法:从文件中导入、从曲线库中选择。 其中曲线库分为公共库和个人库两种,平时浏览的sor文件都可以加载到库中。 第二步

夜晚是传说的博客 5273

LabVIEW调用.so文件的方法

LabVIEW调用.so文件的方法

m0_37878912的博客 3025

springBoot中nacos使用

文档地址 下载地址:https://github.com/alibaba/nacos/releases 官方文档:https://nacos.io/zh-cn/docs/what-is-nacos.html 配置文档:https://nacos.io/zh-cn/docs/system-configurations.html 安装、启动、关闭 1、首先到githup上下载tar的安装包,然后解压: tar -zxvf nacos-server-$version.tar.gz 2、启动命

qq_32748869的博客 3236

【华为OD技术面试真题 - 技术面】- C++面试题(1)

2024华为OD面试手撕代码真题目录以及八股文真题目录

算法大师! 3398

Nacos学习笔记 (5)Nacos整合SpringBoot流程

前提,先下载Nacos并启动 Nacos Server。

喜欢历史的码农 2722

「HTML和CSS入门指南」hr 标签详解

标签是 HTML5 中用于插入水平分割线的标签,常用于在页面中添加分隔线或者段落之间的分割线。通过灵活运用 标签和属性,我们可以帮助用户更好地理解页面内容,同时也可以美化和装饰页面。在实际应用中需要注意避免过度使用 标签,以使页面看起来简洁明了。

a451319296的博客 7663

置顶必读(1) |《滚雪球学 Spring Boot 4.x》专栏目录导航篇(持续更新中)!

🏆 本文收录于 《滚雪球学 Spring Boot 4.x》 专栏。 本专栏面向 有一点 Java 基础,但没有系统学过 Spring Boot 的读者,采用“滚雪球式学习法”:先跑通、再理解、再重构、再上线,最终带你从第一个 Hello API 一路完成一个可部署、可监控、可扩展的后端项目。

**My Coding Family** 8万+

Nacos 发布0.3.0版本,迄今为止看起来最舒服的版本

近日,Nacos0.3.0 正式发布,该版本旨在增强对服务列表,健康状态管理,服务治理,分布式配置管理等方面的管控能力,以便进一步帮助用户降低管理微服务应用架构的成本,...

阿里巴巴中间件 567

基于物联网设计的蜂箱智能监测系统设计

为解决传统养蜂业依赖人工、管理效率低下、干扰蜂群等问题,本项目设计并实现了一套基于物联网(IoT)的蜂箱智能监测系统。

685

Spring Cloud & SpringCloud Alibaba(一套标准化的微服务解决方案)

本文介绍了Spring Cloud微服务架构的基本概念、系统架构演变过程以及核心组件。主要内容包括:Spring Cloud作为微服务落地方案的优势,支持分布式系统开发,提供服务发现、负载均衡等功能;Spring Cloud Alibaba作为补充方案,具备高性能、高可用特性;微服务基础环境搭建步骤,创建父工程聚合管理多个微服务模块。文章通过架构图对比了单体架构、动静分离架构、分布式架构和微服务架构的差异,并提供了Spring Cloud与Spring Boot版本对应关系参考。

m0_48853274的博客 844

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Nacos融合Springcloud时出现的版本问题(2025新版)

这是一个新手在创建cloud项目整合nacos时出现的问题。

weixin_69139579的博客 2423

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

springcloud2024+alibabacloud2023+nacos2.5x 配置

springcloud2024+alibabacloud2023+nacos2.5x 配置

乘茶蛙泳的博客 727

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

RuoYi-Cloud-Plus 2.3.0 正式版发布:全面升级数据权限与工作流引擎

RuoYi-Cloud-Plus作为一款基于Spring Cloud Alibaba的企业级微服务快速开发平台,在2.3.0版本中带来了多项重要改进和新特性。本次更新重点重构了数据权限实现逻辑和工作流模块,同时对系统整体架构进行了优化升级。 ## 核心架构升级 在基础架构方面,本次更新将Spring Boot版本从3.2.11升级到3.4.4,同时Spring Cloud也同步更新至2024....

gitblog_01340的博客 757

021工程微服务治理实战:Spring Cloud Alibaba 2024 全景落地指南

在工程行业数字化转型的复杂场景中,Spring Cloud Alibaba三件套提供了恰到好处的治理能力Nacos解决了多项目、多环境、长周期的配置管理难题,通过Namespace实现物理隔离,通过KMS加密保护商业机密Sentinel应对了建筑行业脉冲式流量特征,从网关到服务层构建多级防护Seata保障了资金流转的最终一致性,AT模式低侵入性适合遗留系统改造技术选型没有银弹,但在建筑工程这个强监管、长周期、高协作的领域,Spring Cloud Alibaba的阿里生产级稳定性和中文生态支持。

经验分享 528

SpringBoot整合Nacos 版本兼容适配 史上最详细教程

本文通过介绍官方文档的方式,教大家学会如何看官方文档、如何使用Nacos、以及如何处理SpringBoot和Nacos的版本兼容问题

qq_40853117的博客 3864

模型直接访问正常,higress转发后报错504 Gateway Timeout: [upstream request timeout]

Higress 路由的默认超时是,而大模型非流式请求动辄几十秒到几分钟,网关等不到上游返回就直接回 504。模型本身没问题(你直连验证过),被截断的是网关这一层。

qq_38636133的博客 221

INFINI Gateway 服务器端口重用(SO_REUSEPORT)实现与分析

TCP 关闭连接是四次挥手。主动关闭的一方(通常是服务器调用close())在发送最后一个 ACK 后,会进入TIME_WAIT状态,持续约2MSL(Maximum Segment Lifetime,Linux 默认 60 秒)。保证最后一个 ACK 能被对方收到(如果 ACK 丢失,对方会重发 FIN,需要能再次应答)。让旧连接的迟到报文在网络中「死掉」,避免同一个四元组被新连接复用后,收到上一个连接的残留数据。解决什么问题能否「同时」多进程监听本质TIME_WAIT 等待❌ 不能。

有问题的请私信或关注v【技术印记】留言 380

AI网关多少钱?MAI Gateway如何帮企业降低AI调用成本

AI调用成本浪费常见于六大漏洞:超设max_tokens、提示词重复计费、模型错配、无限重试、问题重复提问、Key分散导致失控。通过统一接入AI网关,实现配额管控、缓存可观测、用量分层统计、语义复用与Key集中管理,可有效堵住这些“看不见的浪费”。网关价值不在于价格,而在于让成本透明化——先测算浪费金额,再评估投入回报。真正省钱的前提是看清问题,而非盲目采购。

youdiyunan的博客 218

MAI Gateway成本分析:AI网关能省多少钱?TCO计算与对比

TCO并非固定支出,而是由硬件、人力、试错、风险四类可压缩项构成。多数团队高估TCO源于三大惯性:按顶配采购硬件、理想化估算人力、忽视风险成本。通过真实流量测试反推配置、用自动化替代人工运维、前置POC消化不确定性、将合规能力内建,可实现硬件降30%、人力降40%、试错减半、风险可控。综合压缩后TCO整体下降约三分之一,真正实现“省在细节”。自建与采购的压缩空间差异取决于人力与预算相对成本,关键在于识别并压减每一块水分。

youdiyunan的博客 391

AI网关数据安全怎么做?MAI Gateway如何保障AI调用安全合规

本文揭示企业AI调用中的四大数据泄露口:提示词夹带、返回内容风险、Key泄露与日志留存。通过MAIGateway实现脱敏前置、内容防护、Key统一托管及内网部署,构建安全链路。虽工具可覆盖合规要点,但规则维护、误伤权衡、日志监控与渠道协议审核仍需人工持续补位。数据安全本质是“有闸门的管道管理”,工具之外,人防不可缺。

youdiyunan的博客 491

AI网关价格?MAI Gateway免费试用与付费方案详解

搜索“AI网关价格”的用户,真实需求多为试用与成本评估。企业级网关报价无直接可比性,关键在于试用流程与验证重点。建议:明确试用目标,自主部署测试环境,用真实流量验证用量统计、日志排查、模型切换、安全策略及升级流程等五项核心能力。付费方案应关注授权口径、模块边界、服务等级与升级政策,而非单纯比价。试用虽慢,但能规避生产风险;小团队慎用私有化网关。真正有效的路径是“先验证,再谈钱”。

youdiyunan的博客 346

MAI Gateway成本分析:AI网关价格?TCO计算与对比

TCO分析不能替你做决定,但它能让你避免最常见的选型错误:用标价代表总成本,用功能清单代表实际能力。五个块逐项算下来,哪家便宜哪家贵、开源省的钱够不够填人力的坑,答案会比任何人的推荐都可靠。模板拿去就能用。算完要是发现两案接近、拿不定主意,那就选试错成本低的那个——第四块省下来的钱,比你在第一块上磨掉的谈判时间值钱。欢迎联系我们咨询详情!

youdiyunan的博客 431
上一篇: 【学习笔记】企业数字化转型顶层设计与企业架构【TOGAF9.2】-第2章 架构开发方法 --- 2.1ADM架构开发方法概述 + 2.2 ADM周期性阶段目标说明
下一篇: CBA认证(业务架构师认证)简介---适用人群、考试内容与形式、含金量与职业前景,以及‌CBA、TOGAF认证对比表格
飞火流星02027
博客等级 码龄19年 783粉丝 121原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞火流星02027

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值