网关问题
This commit is contained in:
121
urbanLifelineServ/gateway/pom.xml
Normal file
121
urbanLifelineServ/gateway/pom.xml
Normal file
@@ -0,0 +1,121 @@
|
||||
<?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.xyzh</groupId>
|
||||
<artifactId>urban-lifeline</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>gateway</artifactId>
|
||||
<version>${urban-lifeline.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Cloud Gateway -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Nacos 服务注册与发现 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Nacos 配置中心 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 负载均衡 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 认证模块(JWT验证) -->
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-auth</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Redis(用于Token验证、限流等) -->
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类 -->
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-utils</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>org.xyzh.common</groupId>
|
||||
<artifactId>common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Actuator(健康检查) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Log4j2 日志 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- WebFlux(Gateway依赖) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 配置处理 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- FastJson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Lombok -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>org.xyzh.gateway.GatewayApplication</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.xyzh.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
|
||||
|
||||
/**
|
||||
* @description Gateway 网关启动类
|
||||
* @author yslg
|
||||
* @since 2025-12-02
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableDiscoveryClient
|
||||
public class GatewayApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(GatewayApplication.class, args);
|
||||
System.out.println("========================================");
|
||||
System.out.println(" Gateway 网关服务启动成功!");
|
||||
System.out.println("========================================");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.xyzh.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;
|
||||
|
||||
/**
|
||||
* @description Gateway 动态路由配置(Java 代码方式)
|
||||
* @author yslg
|
||||
* @since 2025-12-02
|
||||
*
|
||||
* 这是路由配置的第二种方式,与 application.yml 中的配置二选一或配合使用
|
||||
* 优点:灵活性更高,可以动态添加/修改路由,支持更复杂的路由逻辑
|
||||
*/
|
||||
@Configuration
|
||||
public class GatewayRouteConfig {
|
||||
|
||||
/**
|
||||
* 通过代码方式配置路由(示例,可根据需要启用)
|
||||
*/
|
||||
// @Bean
|
||||
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
|
||||
return builder.routes()
|
||||
// 认证服务路由
|
||||
.route("auth-service", r -> r
|
||||
.path("/auth/**")
|
||||
.filters(f -> f
|
||||
.stripPrefix(1)
|
||||
.addRequestHeader("X-Gateway", "gateway-service")
|
||||
)
|
||||
.uri("lb://auth-service")
|
||||
)
|
||||
|
||||
// 系统服务路由
|
||||
.route("system-service", r -> r
|
||||
.path("/system/**")
|
||||
.filters(f -> f
|
||||
.stripPrefix(1)
|
||||
.addRequestHeader("X-Gateway", "gateway-service")
|
||||
)
|
||||
.uri("lb://system-service")
|
||||
)
|
||||
|
||||
// 日志服务路由
|
||||
.route("log-service", r -> r
|
||||
.path("/log/**")
|
||||
.filters(f -> f
|
||||
.stripPrefix(1)
|
||||
.addRequestHeader("X-Gateway", "gateway-service")
|
||||
)
|
||||
.uri("lb://log-service")
|
||||
)
|
||||
|
||||
// 文件服务路由
|
||||
.route("file-service", r -> r
|
||||
.path("/file/**")
|
||||
.filters(f -> f
|
||||
.stripPrefix(1)
|
||||
.addRequestHeader("X-Gateway", "gateway-service")
|
||||
)
|
||||
.uri("lb://file-service")
|
||||
)
|
||||
|
||||
// WebSocket 路由示例
|
||||
.route("websocket-route", r -> r
|
||||
.path("/ws/**")
|
||||
.uri("lb:ws://system-service")
|
||||
)
|
||||
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态路由刷新端点(如需要)
|
||||
* 可以配合 Nacos 配置中心实现动态路由更新
|
||||
*/
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package org.xyzh.gateway.config;
|
||||
|
||||
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @description 限流配置 - 基于 Redis 的令牌桶算法
|
||||
* @author yslg
|
||||
* @since 2025-12-02
|
||||
*/
|
||||
@Configuration
|
||||
public class RateLimiterConfig {
|
||||
|
||||
/**
|
||||
* 基于 IP 地址的限流
|
||||
*/
|
||||
@Bean
|
||||
public KeyResolver ipKeyResolver() {
|
||||
return exchange -> {
|
||||
String ip = exchange.getRequest().getRemoteAddress() != null
|
||||
? exchange.getRequest().getRemoteAddress().getAddress().getHostAddress()
|
||||
: "unknown";
|
||||
return Mono.just(ip);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于用户 ID 的限流(从请求头获取)
|
||||
*/
|
||||
// @Bean
|
||||
public KeyResolver userKeyResolver() {
|
||||
return exchange -> {
|
||||
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
|
||||
return Mono.just(userId != null ? userId : "anonymous");
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 基于 API 路径的限流
|
||||
*/
|
||||
// @Bean
|
||||
public KeyResolver apiKeyResolver() {
|
||||
return exchange -> Mono.just(exchange.getRequest().getPath().value());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
package org.xyzh.gateway.filter;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.xyzh.common.auth.config.AuthProperties;
|
||||
import org.xyzh.common.auth.contants.AuthContants;
|
||||
import org.xyzh.common.auth.token.TokenParser;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description Gateway 全局认证过滤器 - 用于验证 JWT Token
|
||||
* @author yslg
|
||||
* @since 2025-12-02
|
||||
*/
|
||||
@Component
|
||||
public class AuthGlobalFilter implements GlobalFilter, Ordered {
|
||||
private static final Logger log = LoggerFactory.getLogger(AuthGlobalFilter.class);
|
||||
|
||||
@Autowired
|
||||
private TokenParser tokenParser;
|
||||
|
||||
@Autowired
|
||||
private AuthProperties authProperties;
|
||||
|
||||
private final AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
String path = request.getURI().getPath();
|
||||
|
||||
log.debug("Gateway 请求路径: {}", path);
|
||||
|
||||
// 1. 检查认证功能是否启用
|
||||
if (!authProperties.isEnabled()) {
|
||||
log.debug("认证功能未启用,直接放行");
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
// 2. 检查是否在白名单中
|
||||
if (isWhitelisted(path)) {
|
||||
log.debug("路径在白名单中,跳过认证: {}", path);
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
// 3. 提取 Token
|
||||
String token = extractToken(request);
|
||||
if (!StringUtils.hasText(token)) {
|
||||
log.warn("请求缺少 Token: {}", path);
|
||||
return unauthorizedResponse(exchange, "未提供认证令牌,请先登录");
|
||||
}
|
||||
|
||||
try {
|
||||
// 4. 验证 Token
|
||||
if (tokenParser.isTokenExpired(token)) {
|
||||
log.warn("Token 已过期: {}", path);
|
||||
return unauthorizedResponse(exchange, "认证令牌已过期,请重新登录");
|
||||
}
|
||||
|
||||
// 5. 获取用户信息
|
||||
String userId = tokenParser.getUserIdFromToken(token);
|
||||
if (!StringUtils.hasText(userId)) {
|
||||
log.warn("Token 中未找到用户ID: {}", path);
|
||||
return unauthorizedResponse(exchange, "认证令牌无效");
|
||||
}
|
||||
|
||||
// 6. 验证 Token 有效性
|
||||
if (!tokenParser.validateToken(token, userId)) {
|
||||
log.warn("Token 验证失败: userId={}, path={}", userId, path);
|
||||
return unauthorizedResponse(exchange, "认证令牌验证失败");
|
||||
}
|
||||
|
||||
// 7. 将用户信息添加到请求头中,传递给下游服务
|
||||
ServerHttpRequest mutatedRequest = request.mutate()
|
||||
.header(AuthContants.USER_ID_ATTRIBUTE, userId)
|
||||
.header(AuthContants.TOKEN_ATTRIBUTE, token)
|
||||
.build();
|
||||
|
||||
log.debug("Token 验证成功: userId={}, path={}", userId, path);
|
||||
|
||||
// 8. 继续执行过滤器链
|
||||
return chain.filter(exchange.mutate().request(mutatedRequest).build());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Token 解析或验证异常: path={}, error={}", path, e.getMessage(), e);
|
||||
return unauthorizedResponse(exchange, "认证令牌解析失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查路径是否在白名单中
|
||||
*/
|
||||
private boolean isWhitelisted(String path) {
|
||||
// 1. 检查认证相关接口
|
||||
if (authProperties.getAuthPaths() != null) {
|
||||
for (String pattern : authProperties.getAuthPaths()) {
|
||||
if (pattern != null && pathMatcher.match(pattern, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 检查通用白名单
|
||||
if (authProperties.getWhitelist() != null) {
|
||||
for (String pattern : authProperties.getWhitelist()) {
|
||||
if (pattern != null && pathMatcher.match(pattern, path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求头中提取 Token
|
||||
*/
|
||||
private String extractToken(ServerHttpRequest request) {
|
||||
List<String> headers = request.getHeaders().get(authProperties.getTokenHeader());
|
||||
if (headers == null || headers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String header = headers.get(0);
|
||||
if (!StringUtils.hasText(header)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 支持 Bearer 前缀
|
||||
String prefix = authProperties.getTokenPrefix();
|
||||
if (StringUtils.hasText(prefix) && header.startsWith(prefix)) {
|
||||
return header.substring(prefix.length()).trim();
|
||||
}
|
||||
|
||||
// 也支持直接传递 Token(不带前缀)
|
||||
return header.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回未授权响应
|
||||
*/
|
||||
private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String message) {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
response.setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
ResultDomain<Object> result = ResultDomain.failure(HttpStatus.UNAUTHORIZED.value(), message);
|
||||
String json = JSON.toJSONString(result);
|
||||
DataBuffer buffer = response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return response.writeWith(Mono.just(buffer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
// 优先级设置为最高,确保在其他过滤器之前执行
|
||||
return Ordered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.xyzh.gateway.filter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
|
||||
import org.springframework.cloud.gateway.filter.GlobalFilter;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* @description Gateway 全局日志过滤器 - 记录请求信息
|
||||
* @author yslg
|
||||
* @since 2025-12-02
|
||||
*/
|
||||
@Component
|
||||
public class LogGlobalFilter implements GlobalFilter, Ordered {
|
||||
private static final Logger log = LoggerFactory.getLogger(LogGlobalFilter.class);
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
String path = request.getURI().getPath();
|
||||
String method = request.getMethod().name();
|
||||
String remoteAddress = request.getRemoteAddress() != null
|
||||
? request.getRemoteAddress().getAddress().getHostAddress()
|
||||
: "unknown";
|
||||
|
||||
log.info("==> Gateway 请求: {} {} | 来源: {}", method, path, remoteAddress);
|
||||
|
||||
return chain.filter(exchange).then(
|
||||
Mono.fromRunnable(() -> {
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
int statusCode = exchange.getResponse().getStatusCode() != null
|
||||
? exchange.getResponse().getStatusCode().value()
|
||||
: 0;
|
||||
|
||||
log.info("<== Gateway 响应: {} {} | 状态: {} | 耗时: {}ms",
|
||||
method, path, statusCode, duration);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
// 优先级设置较低,在认证过滤器之后执行
|
||||
return Ordered.LOWEST_PRECEDENCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package org.xyzh.gateway.handler;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||
import org.springframework.cloud.gateway.support.NotFoundException;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @description Gateway 全局异常处理器
|
||||
* @author yslg
|
||||
* @since 2025-12-02
|
||||
*/
|
||||
@Component
|
||||
@Order(-1) // 优先级设置为最高
|
||||
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {
|
||||
private static final Logger log = LoggerFactory.getLogger(GatewayExceptionHandler.class);
|
||||
|
||||
@Override
|
||||
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
|
||||
if (response.isCommitted()) {
|
||||
return Mono.error(ex);
|
||||
}
|
||||
|
||||
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
ResultDomain<Object> result;
|
||||
HttpStatus httpStatus;
|
||||
|
||||
// 根据不同异常类型返回不同的错误信息
|
||||
if (ex instanceof NotFoundException) {
|
||||
log.error("服务未找到: {}", ex.getMessage());
|
||||
httpStatus = HttpStatus.SERVICE_UNAVAILABLE;
|
||||
result = ResultDomain.failure(httpStatus.value(), "服务暂时不可用: " + ex.getMessage());
|
||||
} else if (ex instanceof ResponseStatusException rse) {
|
||||
log.error("响应状态异常: {}", rse.getMessage());
|
||||
httpStatus = (HttpStatus) rse.getStatusCode();
|
||||
result = ResultDomain.failure(httpStatus.value(), rse.getReason());
|
||||
} else if (ex instanceof IllegalStateException) {
|
||||
log.error("非法状态异常: {}", ex.getMessage());
|
||||
httpStatus = HttpStatus.BAD_REQUEST;
|
||||
result = ResultDomain.failure(httpStatus.value(), "请求参数错误: " + ex.getMessage());
|
||||
} else {
|
||||
log.error("Gateway 内部错误", ex);
|
||||
httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
result = ResultDomain.failure(httpStatus.value(), "网关内部错误,请稍后重试");
|
||||
}
|
||||
|
||||
response.setStatusCode(httpStatus);
|
||||
|
||||
String json = JSON.toJSONString(result);
|
||||
DataBuffer buffer = response.bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
return response.writeWith(Mono.just(buffer));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
# 开发环境可以添加更详细的路由配置或测试路由
|
||||
|
||||
# Nacos 管理界面路由(开发专用)
|
||||
- id: nacos-console
|
||||
uri: http://${NACOS_SERVER_ADDR:localhost:8848}
|
||||
predicates:
|
||||
- Path=/nacos/**
|
||||
|
||||
# 开发环境日志
|
||||
logging:
|
||||
level:
|
||||
org.springframework.cloud.gateway: DEBUG
|
||||
org.springframework.web.reactive: DEBUG
|
||||
reactor.netty: DEBUG
|
||||
org.xyzh: DEBUG
|
||||
133
urbanLifelineServ/gateway/src/main/resources/application.yml
Normal file
133
urbanLifelineServ/gateway/src/main/resources/application.yml
Normal file
@@ -0,0 +1,133 @@
|
||||
server:
|
||||
port: 8080
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: gateway-service
|
||||
|
||||
# 配置中心
|
||||
cloud:
|
||||
nacos:
|
||||
discovery:
|
||||
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
|
||||
namespace: dev
|
||||
group: DEFAULT_GROUP
|
||||
config:
|
||||
server-addr: ${NACOS_SERVER_ADDR:localhost:8848}
|
||||
file-extension: yml
|
||||
namespace: dev
|
||||
group: DEFAULT_GROUP
|
||||
|
||||
# Gateway 路由配置
|
||||
gateway:
|
||||
# 服务发现路由(自动路由)
|
||||
discovery:
|
||||
locator:
|
||||
enabled: false # 关闭自动路由,使用手动配置
|
||||
|
||||
# 手动配置路由
|
||||
routes:
|
||||
# ==================== 认证服务路由 ====================
|
||||
- id: auth-service
|
||||
uri: lb://auth-service
|
||||
predicates:
|
||||
- Path=/auth/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
- name: RequestRateLimiter
|
||||
args:
|
||||
redis-rate-limiter.replenishRate: 100
|
||||
redis-rate-limiter.burstCapacity: 200
|
||||
|
||||
# ==================== 系统服务路由 ====================
|
||||
- id: system-service
|
||||
uri: lb://system-service
|
||||
predicates:
|
||||
- Path=/system/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
|
||||
# ==================== 日志服务路由 ====================
|
||||
- id: log-service
|
||||
uri: lb://log-service
|
||||
predicates:
|
||||
- Path=/log/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
|
||||
# ==================== 文件服务路由 ====================
|
||||
- id: file-service
|
||||
uri: lb://file-service
|
||||
predicates:
|
||||
- Path=/file/**
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
|
||||
# 全局跨域配置
|
||||
globalcors:
|
||||
cors-configurations:
|
||||
'[/**]':
|
||||
allowedOriginPatterns: "*"
|
||||
allowedMethods:
|
||||
- GET
|
||||
- POST
|
||||
- PUT
|
||||
- DELETE
|
||||
- OPTIONS
|
||||
allowedHeaders: "*"
|
||||
allowCredentials: true
|
||||
maxAge: 3600
|
||||
|
||||
# Redis 配置(用于限流、缓存)
|
||||
data:
|
||||
redis:
|
||||
host: ${REDIS_HOST:localhost}
|
||||
port: ${REDIS_PORT:6379}
|
||||
database: 0
|
||||
timeout: 5000ms
|
||||
lettuce:
|
||||
pool:
|
||||
max-active: 20
|
||||
max-wait: -1ms
|
||||
max-idle: 10
|
||||
min-idle: 5
|
||||
|
||||
# 认证配置
|
||||
auth:
|
||||
enabled: true
|
||||
token-header: Authorization
|
||||
token-prefix: "Bearer "
|
||||
# 认证接口白名单(login/logout/captcha/refresh)
|
||||
auth-paths:
|
||||
- /auth/login
|
||||
- /auth/logout
|
||||
- /auth/captcha
|
||||
- /auth/refresh
|
||||
# 通用白名单(Swagger、健康检查等)
|
||||
whitelist:
|
||||
- /actuator/**
|
||||
- /v3/api-docs/**
|
||||
- /swagger-ui/**
|
||||
- /swagger-resources/**
|
||||
- /webjars/**
|
||||
- /doc.html
|
||||
- /favicon.ico
|
||||
- /error
|
||||
|
||||
# Actuator 监控端点
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,info,gateway
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
org.springframework.cloud.gateway: DEBUG
|
||||
org.xyzh.gateway: DEBUG
|
||||
pattern:
|
||||
console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"
|
||||
Reference in New Issue
Block a user