利用filter设置requestId
import cn.hutool.core.lang.UUID;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Slf4j
@Component
public class RequestIdRelayFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 1.生成 RequestIdString requestId = UUID.randomUUID().toString(true);// 2.保存到日志变量池MDC.put(REQUEST_ID_HEADER, requestId); // "requestId"// 3.更新请求头,添加标示String path = exchange.getRequest().getPath().toString();exchange = exchange.mutate().request(b -> {// 3.1.添加请求id标示b.header(REQUEST_ID_HEADER, requestId);// 3.2.添加网关标示if (!path.startsWith("/ps/notify")) {b.header(REQUEST_FROM_HEADER, GATEWAY_ORIGIN_NAME); // "x-request-from" "gateway"}}).build();return chain.filter(exchange);}@Overridepublic int getOrder() {return Ordered.HIGHEST_PRECEDENCE;}
}
响应对象R
@Data
@ApiModel(description = "通用响应结果")
public class R<T> {@ApiModelProperty(value = "业务状态码,200-成功,其它-失败")private int code;@ApiModelProperty(value = "响应消息", example = "OK")private String msg;@ApiModelProperty(value = "响应数据")private T data;@ApiModelProperty(value = "请求id", example = "1af123c11412e")private String requestId;public static R<Void> ok() {return new R<Void>(SUCCESS, OK, null);}public static <T> R<T> ok(T data) {return new R<>(SUCCESS, OK, data);}public static <T> R<T> error(String msg) {return new R<>(FAILED, msg, null);}public static <T> R<T> error(int code, String msg) {return new R<>(code, msg, null);}public R() {}public R(int code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;this.requestId = MDC.get(Constant.REQUEST_ID_HEADER);}public boolean success(){return code == SUCCESS;}public R<T> requestId(String requestId) {this.requestId = requestId;return this;}
}
处理Responsebody切面
参考https://blog.csdn.net/weixin_45734473/article/details/133343637
import org.slf4j.MDC;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;@RestControllerAdvice
public class WrapperResponseBodyAdvice implements ResponseBodyAdvice<Object> {//Spring MVC的ResponseBodyAdvice接口中的supports方法主要是用于判断是否符合处理条件。
//这个方法的返回值是一个布尔值,当返回值为true时,会调用beforeBodyWrite方法对返回值进行处理,否则不进行处理。@Overridepublic boolean supports(MethodParameter returnType, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {return returnType.getParameterType() != R.class && WebUtils.isGatewayRequest();}
// 上面的WebUtils.isGatewayRequest()
// public static boolean isGatewayRequest() {
// String originName = getHeader(Constant.REQUEST_FROM_HEADER); // "x-request-from"
// return Constant.GATEWAY_ORIGIN_NAME.equals(originName); // "gateway"
// }@Overridepublic Object beforeBodyWrite(Object body, @NonNull MethodParameter returnType, @NonNull MediaType selectedContentType,@NonNull Class<? extends HttpMessageConverter<?>> selectedConverterType,@NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response) {// swagger2默认的url后缀if (request.getURI().getPath().equals("/v2/api-docs")){return body;}if (body == null) {return R.ok().requestId(MDC.get(Constant.REQUEST_ID_HEADER));// "requestId"}if(body instanceof R){return body;}return R.ok(body).requestId(MDC.get(Constant.REQUEST_ID_HEADER)); //"requestId"}
}
MDC实现日志的链路追踪
详情参考https://mp.weixin.qq.com/s?__biz=MzAxMjY5NDU2Ng==&mid=2651854053&idx=2&sn=495849a51b126ce157fe7d034f82a4f1&chksm=804951acb73ed8ba8ea6fb11688655cbe76c20913a8e464acc11d02f05ee48af65afed59a9b6&scene=27