Compare commits

..

11 Commits

Author SHA1 Message Date
6bfc845693 放行 2025-10-23 23:14:22 +08:00
6b50bfaeb4 notify 2025-09-29 02:21:28 +08:00
50f3579f6a Merge branch 'main' of http://115.190.8.52:3000/sczx_group/sczx_gateway 2025-09-11 01:11:21 +08:00
47cbb100d6 从nacos拉取配置 2025-09-11 01:11:17 +08:00
094044ed73 调整回来 2025-09-08 18:18:05 +08:00
884967423f 尝试网关路由打印 2025-09-08 18:10:01 +08:00
35b3cbfdc0 再修改 2025-09-08 17:47:28 +08:00
8b5648a3dc 修改返回值日志 2025-09-08 17:43:14 +08:00
bb92857db9 网关日志调整 2025-09-08 17:29:32 +08:00
ee7556f706 Merge branch 'main' of http://115.190.8.52:3000/sczx_group/sczx_gateway 2025-09-03 00:59:12 +08:00
ad54c0e1b5 支付服务放行 2025-09-03 00:59:07 +08:00
8 changed files with 79 additions and 83 deletions

View File

@ -74,6 +74,11 @@
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId> <artifactId>spring-cloud-starter-loadbalancer</artifactId>

View File

@ -40,7 +40,7 @@ public class CustomRouteConfig {
RouteLocatorBuilder.Builder routesBuilder = builder.routes(); RouteLocatorBuilder.Builder routesBuilder = builder.routes();
// 定义需要路由的服务列表 // 定义需要路由的服务列表
String[] serviceNames = {"sczx-user", "sczx-store", "sczx-car", "sczx-order", "sczx-sync", "sczx-singlepay"}; String[] serviceNames = {"sczx-user", "sczx-store", "sczx-car", "sczx-order", "sczx-sync", "sczx-singlepay", "sczx-notify"};
// 为每个服务添加路由规则(如果服务存在) // 为每个服务添加路由规则(如果服务存在)
for (String serviceName : serviceNames) { for (String serviceName : serviceNames) {

View File

@ -59,7 +59,7 @@ public class DynamicRouteConfig implements RouteDefinitionLocator {
List<RouteDefinition> routeDefinitions = new ArrayList<>(); List<RouteDefinition> routeDefinitions = new ArrayList<>();
// 定义需要路由的服务列表 // 定义需要路由的服务列表
String[] serviceNames = {"sczx-user", "sczx-store", "sczx-car", "sczx-order", "sczx-sync", "sczx-singlepay"}; String[] serviceNames = {"sczx-user", "sczx-store", "sczx-car", "sczx-order", "sczx-sync", "sczx-singlepay", "sczx-notify"};
// 为每个服务添加路由规则(如果服务存在) // 为每个服务添加路由规则(如果服务存在)
for (String serviceName : serviceNames) { for (String serviceName : serviceNames) {

View File

@ -42,7 +42,11 @@ public class AuthGlobalFilter implements GlobalFilter, Ordered {
"/zc/car/carModel/pageStoreCarModel", "/zc/car/carModel/pageStoreCarModel",
//同步服务都放行 //同步服务都放行
"/zc/sync/**", "/zc/sync/**",
//支付服务都放行
"/zc/singlepay/**",
"/zc/notify/**",
"/zc/order/pubOrder/**", "/zc/order/pubOrder/**",
"/zc/order/verify/**",
// Swagger 放行 // Swagger 放行

View File

@ -20,6 +20,7 @@ import org.springframework.web.server.ServerWebExchangeDecorator;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.UUID; import java.util.UUID;
@ -64,7 +65,8 @@ public class LoggingGlobalFilter implements GlobalFilter, Ordered {
private static class CustomExchange extends ServerWebExchangeDecorator implements CustomExchangeInterface { private static class CustomExchange extends ServerWebExchangeDecorator implements CustomExchangeInterface {
private final StringBuilder requestBody = new StringBuilder(); private final StringBuilder requestBody = new StringBuilder();
private String responseBody; private final StringBuilder responseBodyBuilder = new StringBuilder();
public CustomExchange(ServerWebExchange delegate) { public CustomExchange(ServerWebExchange delegate) {
@ -88,25 +90,31 @@ public class LoggingGlobalFilter implements GlobalFilter, Ordered {
}; };
} }
@Override @Override
public ServerHttpResponse getResponse() { public ServerHttpResponse getResponse() {
return new ServerHttpResponseDecorator(super.getResponse()) { ServerHttpResponse originalResponse = super.getResponse();
private final StringBuilder responseBodyBuilder = new StringBuilder(); DataBufferFactory bufferFactory = originalResponse.bufferFactory();
return new ServerHttpResponseDecorator(originalResponse) {
@Override @Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) { if (body instanceof Flux) {
return super.writeWith(Flux.from(body) Flux<? extends DataBuffer> flux = (Flux<? extends DataBuffer>) body;
.doOnNext(buffer -> { return super.writeWith(flux.doOnNext(dataBuffer -> {
DataBufferUtils.join(Flux.just(buffer)) // 复制数据以避免修改原始缓冲区
.map(dataBuffer -> { DataBuffer duplicate = dataBuffer.factory().allocateBuffer(dataBuffer.readableByteCount());
byte[] content = new byte[dataBuffer.readableByteCount()]; duplicate.write(dataBuffer);
dataBuffer.read(content);
responseBody = new String(content, StandardCharsets.UTF_8); // 读取数据内容用于日志记录
return dataBuffer; byte[] bytes = new byte[duplicate.readableByteCount()];
}) duplicate.read(bytes);
.subscribe(); String bodyContent = new String(bytes, StandardCharsets.UTF_8);
})); responseBodyBuilder.append(bodyContent);
// 释放复制的缓冲区
DataBufferUtils.release(duplicate);
}));
} }
return super.writeWith(body); return super.writeWith(body);
} }
@ -120,7 +128,7 @@ public class LoggingGlobalFilter implements GlobalFilter, Ordered {
@Override @Override
public String getResponseBody() { public String getResponseBody() {
return responseBody; return responseBodyBuilder.toString();
} }
} }

View File

@ -23,6 +23,7 @@ import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -30,38 +31,46 @@ import java.util.List;
//@Configuration //@Configuration
public class ResponseLogGlobalFilter implements GlobalFilter, Ordered { public class ResponseLogGlobalFilter implements GlobalFilter, Ordered {
@Override @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
try { try {
ServerHttpResponse originalResponse = exchange.getResponse(); ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory(); DataBufferFactory bufferFactory = originalResponse.bufferFactory();
HttpStatus statusCode = originalResponse.getStatusCode(); HttpStatus statusCode = originalResponse.getStatusCode();
// 排除特定路径避免处理Swagger等静态资源
String path = exchange.getRequest().getURI().getPath();
if (path.contains("/v2/api-docs") ||
path.contains("/swagger") ||
path.contains("/webjars")) {
return chain.filter(exchange);
}
if (statusCode != HttpStatus.OK) { if (statusCode != HttpStatus.OK) {
return chain.filter(exchange);//降级处理返回数据 return chain.filter(exchange);//降级处理返回数据
} }
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override @Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) { if (body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = Flux.from(body); Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> { return super.writeWith(fluxBody.map(dataBuffer -> {
// 复制数据以避免修改原始缓冲区
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
DataBufferUtils.release(dataBuffer);
// 合并多个流集合,解决返回体分段传输 // 排除Excel导出不是application/json不打印。若请求是上传图片则在最上面判断。
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer buff = dataBufferFactory.join(dataBuffers);
byte[] content = new byte[buff.readableByteCount()];
buff.read(content);
DataBufferUtils.release(buff);//释放掉内存
//排除Excel导出不是application/json不打印。若请求是上传图片则在最上面判断。
MediaType contentType = originalResponse.getHeaders().getContentType(); MediaType contentType = originalResponse.getHeaders().getContentType();
if (!MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) { if (contentType == null || !MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
return bufferFactory.wrap(content); return bufferFactory.wrap(content);
} }
// 构建返回日志 // 构建返回日志
String joinData = new String(content); String joinData = new String(content, StandardCharsets.UTF_8);
String result = modifyBody(joinData); String result = modifyBody(joinData);
List<Object> rspArgs = new ArrayList<>(); List<Object> rspArgs = new ArrayList<>();
rspArgs.add(originalResponse.getStatusCode().value()); rspArgs.add(originalResponse.getStatusCode().value());
@ -69,8 +78,8 @@ public class ResponseLogGlobalFilter implements GlobalFilter, Ordered {
rspArgs.add(result); rspArgs.add(result);
log.info("<-- {} {}\n{}", rspArgs.toArray()); log.info("<-- {} {}\n{}", rspArgs.toArray());
getDelegate().getHeaders().setContentLength(result.getBytes().length); // 返回处理后的内容
return bufferFactory.wrap(result.getBytes()); return bufferFactory.wrap(result.getBytes(StandardCharsets.UTF_8));
})); }));
} else { } else {
log.error("<-- {} 响应code异常", getStatusCode()); log.error("<-- {} 响应code异常", getStatusCode());
@ -88,14 +97,23 @@ public class ResponseLogGlobalFilter implements GlobalFilter, Ordered {
@Override @Override
public int getOrder() { public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE; // 设置较低优先级,确保在其他过滤器之后执行
return Ordered.LOWEST_PRECEDENCE - 1;
} }
//返回统一的JSON日期数据 2024-02-23 11:00 null转空字符串 //返回统一的JSON日期数据 2024-02-23 11:00 null转空字符串
private String modifyBody(String jsonStr){ private String modifyBody(String jsonStr){
JSONObject json = JSON.parseObject(jsonStr, Feature.AllowISO8601DateFormat); if (jsonStr == null || jsonStr.isEmpty()) {
JSONObject.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm"; return jsonStr;
return JSONObject.toJSONString(json, (ValueFilter) (object, name, value) -> value == null ? "" : value, SerializerFeature.WriteDateUseDateFormat); }
try {
JSONObject json = JSON.parseObject(jsonStr, Feature.AllowISO8601DateFormat);
JSONObject.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm";
return JSONObject.toJSONString(json, (ValueFilter) (object, name, value) -> value == null ? "" : value, SerializerFeature.WriteDateUseDateFormat);
} catch (Exception e) {
// 如果不是有效的JSON直接返回原始字符串
return jsonStr;
}
} }
} }

View File

@ -1,55 +1,6 @@
server:
port: 8089
shutdown: graceful # 启用优雅停机
spring: spring:
application: application:
name: sczx-gateway name: sczx-gateway
cloud:
# gateway:
# discovery:
# locator:
# enabled: true # 开启从注册中心动态获取路由
# lower-case-service-id: true # 服务名转小写
# routes:
# - id: sczx_user
## uri: http://172.18.0.4:8081
# uri: lb://sczx_user
# predicates:
# - Path=/zc/user/**
# filters:
# - StripPrefix=2
# - id: sczx_store
# uri: lb://sczx_store
# predicates:
# - Path=/zc/store/**
# filters:
# - StripPrefix=2
nacos:
discovery:
server-addr: 115.190.8.52:8848 # Nacos 地址
group: DEFAULT_GROUP
watch-delay: 120000 # 60秒刷新一次
loadbalancer:
ribbon:
enabled: false
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
auth:
secret-key: his-is-a-very-long-and-secure-secret-key-for-jwt-signing-please-dont-use-short-keys
token-expiration: 86400000 # 24小时
#logging:
# level:
# org.springframework.cloud.gateway: DEBUG
# org.springframework.cloud.loadbalancer: DEBUG
# reactor.core.publisher: DEBUG

View File

@ -0,0 +1,10 @@
spring:
application:
name: sczx-gateway # 应用名称,对应 Nacos 配置的 dataId
cloud:
nacos:
server-addr: 115.190.8.52:8848 # Nacos 服务器地址
config:
group: DEFAULT_GROUP # 配置分组
file-extension: yaml # 配置文件格式
timeout: 5000 # 配置读取超时时间