fix(gateway): include stable request and trace ids in security errors

This commit is contained in:
2026-08-11 10:35:01 +08:00
parent 0e47155649
commit 4e79287a35
4 changed files with 106 additions and 7 deletions
@@ -1,6 +1,7 @@
package com.baiyue.gateway.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.baiyue.gateway.filter.CorrelationIdWebFilter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -69,9 +70,14 @@ public class GatewaySecurityConfig {
ObjectMapper mapper, HttpStatus status, String code, String message) {
exchange.getResponse().setStatusCode(status);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
String requestId = CorrelationIdWebFilter.ensureRequestId(exchange);
String traceId = CorrelationIdWebFilter.ensureTraceId(exchange);
exchange.getResponse().getHeaders().set(CorrelationIdWebFilter.HEADER, requestId);
exchange.getResponse().getHeaders().set(CorrelationIdWebFilter.TRACE_HEADER, traceId);
Map<String, Object> body = new LinkedHashMap<>();
body.put("code", code); body.put("message", message); body.put("data", null);
body.put("requestId", exchange.getRequest().getId()); body.put("timestamp", Instant.now().toString());
body.put("requestId", requestId); body.put("traceId", traceId);
body.put("timestamp", Instant.now().toString());
try {
byte[] bytes = mapper.writeValueAsBytes(body);
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(bytes)));
@@ -14,19 +14,36 @@ import java.util.UUID;
@Component
public class CorrelationIdWebFilter implements WebFilter, Ordered {
public static final String HEADER = "X-Request-Id";
public static final String TRACE_HEADER = "X-Trace-Id";
public static final String REQUEST_ID_ATTRIBUTE = CorrelationIdWebFilter.class.getName() + ".requestId";
public static final String TRACE_ID_ATTRIBUTE = CorrelationIdWebFilter.class.getName() + ".traceId";
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String requestId = validRequestId(exchange.getRequest().getHeaders())
? exchange.getRequest().getHeaders().getFirst(HEADER)
: UUID.randomUUID().toString();
String requestId = ensureRequestId(exchange);
String traceId = ensureTraceId(exchange);
exchange.getResponse().getHeaders().set(HEADER, requestId);
exchange.getResponse().getHeaders().set(TRACE_HEADER, traceId);
return chain.filter(exchange);
}
private static boolean validRequestId(HttpHeaders headers) {
String value = headers.getFirst(HEADER);
return value != null && !value.isBlank() && value.length() <= 128
public static String ensureRequestId(ServerWebExchange exchange) {
return (String) exchange.getAttributes().computeIfAbsent(REQUEST_ID_ATTRIBUTE, key -> {
HttpHeaders headers = exchange.getRequest().getHeaders();
return validRequestId(headers.getFirst(HEADER))
? headers.getFirst(HEADER) : UUID.randomUUID().toString();
});
}
public static String ensureTraceId(ServerWebExchange exchange) {
return (String) exchange.getAttributes().computeIfAbsent(TRACE_ID_ATTRIBUTE, key -> {
String incoming = exchange.getRequest().getHeaders().getFirst(TRACE_HEADER);
return validRequestId(incoming) ? incoming : UUID.randomUUID().toString();
});
}
private static boolean validRequestId(String value) {
return value != null && !value.isBlank() && value.length() >= 16 && value.length() <= 128
&& value.chars().allMatch(character -> character >= 0x21 && character <= 0x7e);
}