Spring Cloud Gateway自定义路由失效问题求助
Spring Cloud Gateway自定义路由返回404问题
我正在搭建Spring Cloud Gateway服务器,为两个已开发的微服务配置自定义路由。启动网关后,通过actuator/gateway/routes能看到自定义路由已注册,但访问/api/account或/api/profile这类自定义路径时返回404,改用/accountsservice这类自动生成的路径却能正常请求。尝试关闭lowerCaseServiceId后问题依旧,求解决。
网关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 https://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> <version>3.1.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.geminibank</groupId> <artifactId>apigateway</artifactId> <version>0.0.1-SNAPSHOT</version> <name>apigateway</name> <description>Demo project for Spring Boot</description> <properties> <java.version>17</java.version> <spring-cloud.version>2022.0.3</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
网关配置文件
server.port=8090 spring.application.name = apigateway spring.cloud.gateway.discovery.locator.enabled = true spring.cloud.gateway.discovery.locator.lowerCaseServiceId = true management.endpoint.gateway.enabled=true management.endpoints.web.exposure.include=health,gateway eureka.instance.prefer-ip-address = true eureka.instance.hostname=localhost eureka.client.fetch-registry = true eureka.client.register-with-eureka = true eureka.client.serviceUrl.defaultZone = http://${eureka.instance.hostname}:8082/eureka/
Gateway配置类
@Configuration public class GatewayConfig { @Bean public RouteLocator customeRouteLocator(RouteLocatorBuilder builder) { RouteLocator routes = builder.routes() .route("profile-service", p -> p .path("/api/profile/**") .uri("lb://PROFILESERVICE")) .route("account-service", p -> p .path("/api/account/**") .uri("lb://ACCOUNTSSERVICE")) .build(); routes.getRoutes().log(); return routes; } }
已注册路由列表(来自actuator/gateway/routes)
[ { "predicate": "Paths: [/api/profile/**], match trailing slash: true", "route_id": "profile-service", "filters": [], "uri": "lb://PROFILESERVICE", "order": 0 }, { "predicate": "Paths: [/api/account/**], match trailing slash: true", "route_id": "account-service", "filters": [], "uri": "lb://ACCOUNTSSERVICE", "order": 0 }, { "predicate": "Paths: [/profileservice/**], match trailing slash: true", "metadata": { "jmx.port": "51067", "management.port": "8083" }, "route_id": "ReactiveCompositeDiscoveryClient_PROFILESERVICE", "filters": [ "[[RewritePath /profileservice/?(?<remaining>.*) = '/${remaining}'], order = 1]" ], "uri": "lb://PROFILESERVICE", "order": 0 }, { "predicate": "Paths: [/accountsservice/**], match trailing slash: true", "metadata": { "jmx.port": "51001", "management.port": "8084" }, "route_id": "ReactiveCompositeDiscoveryClient_ACCOUNTSSERVICE", "filters": [ "[[RewritePath /accountsservice/?(?<remaining>.*) = '/${remaining}'], order = 1]" ], "uri": "lb://ACCOUNTSSERVICE", "order": 0 }, { "predicate": "Paths: [/apigateway/**], match trailing slash: true", "metadata": { "jmx.port": "59682", "management.port": "8090" }, "route_id": "ReactiveCompositeDiscoveryClient_APIGATEWAY", "filters": [ "[[RewritePath /apigateway/?(?<remaining>.*) = '/${remaining}'], order = 1]" ], "uri": "lb://APIGATEWAY", "order": 0 } ]
问题原因及解决方案
核心原因
自动生成的服务路由(如/accountsservice/**)带有RewritePath过滤器,会将请求路径中的服务名前缀移除后转发到微服务;而你的自定义路由没有配置该过滤器,导致完整的/api/account/**路径被转发到微服务,但微服务本身的接口路径可能并不包含/api/account前缀,因此返回404。
修复步骤
修改自定义路由配置,添加RewritePath过滤器,移除自定义前缀后再转发:
修改后的Gateway配置类
@Configuration public class GatewayConfig { @Bean public RouteLocator customeRouteLocator(RouteLocatorBuilder builder) { return builder.routes() .route("profile-service", p -> p .path("/api/profile/**") // 移除/api/profile前缀,转发剩余路径到微服务 .filters(f -> f.rewritePath("/api/profile/(?<remaining>.*)", "/${remaining}")) .uri("lb://PROFILESERVICE")) .route("account-service", p -> p .path("/api/account/**") // 移除/api/account前缀,转发剩余路径到微服务 .filters(f -> f.rewritePath("/api/account/(?<remaining>.*)", "/${remaining}")) .uri("lb://ACCOUNTSSERVICE")) .build(); } }
额外检查点
- 确认微服务接口路径:确保微服务的接口路径确实不包含
/api/account或/api/profile前缀。如果微服务接口本身带有这些前缀,则不需要添加RewritePath过滤器。 - Eureka服务名匹配:检查
lb://PROFILESERVICE和lb://ACCOUNTSSERVICE中的服务名是否与Eureka中注册的微服务名称完全一致(注意大小写,Eureka服务名默认区分大小写)。 - 路由优先级:如果自定义路由和自动生成路由的order相同,可能存在匹配顺序问题,可以通过
order()方法调整自定义路由的优先级,比如设置为order(-1)让其先匹配。
内容的提问来源于stack exchange,提问作者Shady98
相关产品推荐
相关产品推荐

