• Springcloudgateway如何在全局过滤器中获得请求体和响应体


    需要使用请求装饰类和响应装饰类,把请求体和响应体保存一下,再在全局Post过滤器里面获得该请求体。

     请求装饰类

    1. package com.chilun.apiopenspace.gateway.filter;
    2. import com.chilun.apiopenspace.gateway.Utils.LogCacheMap;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.jetbrains.annotations.NotNull;
    5. import org.springframework.core.io.buffer.DataBuffer;
    6. import org.springframework.core.io.buffer.DataBufferFactory;
    7. import org.springframework.core.io.buffer.DataBufferUtils;
    8. import org.springframework.http.server.reactive.ServerHttpRequest;
    9. import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
    10. import org.springframework.web.server.ServerWebExchange;
    11. import reactor.core.publisher.Flux;
    12. import java.nio.charset.StandardCharsets;
    13. /**
    14. * @author 齿轮
    15. * @date 2024-02-29-17:51
    16. */
    17. @Slf4j
    18. public class LoggingRequestDecorator extends ServerHttpRequestDecorator {
    19. private final String uuid;
    20. private final DataBufferFactory bufferFactory;
    21. public LoggingRequestDecorator(ServerHttpRequest delegate, ServerWebExchange exchange, String uuid) {
    22. super(delegate);
    23. this.bufferFactory = exchange.getResponse().bufferFactory();
    24. this.uuid = uuid;
    25. }
    26. @NotNull
    27. @Override
    28. public Flux getBody() {
    29. Flux originalBody = super.getBody();
    30. return originalBody.map(dataBuffer -> {
    31. byte[] content = new byte[dataBuffer.readableByteCount()];
    32. dataBuffer.read(content);
    33. // 将请求体数据转换为字符串,并保存到缓存中
    34. String requestBody = new String(content, StandardCharsets.UTF_8);
    35. log.info("Request Body: " + requestBody);
    36. LogCacheMap.saveRequest(uuid, requestBody);
    37. //重新包装了DataBuffer,所以要释放原始的DataBuffer
    38. DataBufferUtils.release(dataBuffer);
    39. // 返回新的DataBuffer
    40. return bufferFactory.wrap(content);
    41. });
    42. }
    43. }

    响应装饰类

    1. package com.chilun.apiopenspace.gateway.filter;
    2. import com.chilun.apiopenspace.gateway.Utils.LogCacheMap;
    3. import lombok.extern.slf4j.Slf4j;
    4. import org.springframework.core.io.buffer.DataBuffer;
    5. import org.springframework.core.io.buffer.DataBufferFactory;
    6. import org.springframework.core.io.buffer.DataBufferUtils;
    7. import org.springframework.core.io.buffer.DefaultDataBufferFactory;
    8. import org.springframework.http.server.reactive.ServerHttpResponse;
    9. import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
    10. import reactor.core.publisher.Flux;
    11. import reactor.core.publisher.Mono;
    12. import java.nio.charset.StandardCharsets;
    13. /**
    14. * @author 齿轮
    15. * @date 2024-02-29-17:51
    16. */
    17. @Slf4j
    18. public class LoggingResponseDecorator extends ServerHttpResponseDecorator {
    19. private final DataBufferFactory bufferFactory;
    20. private final String uuid;
    21. public LoggingResponseDecorator(ServerHttpResponse delegate, String uuid) {
    22. super(delegate);
    23. this.bufferFactory = delegate.bufferFactory();
    24. this.uuid = uuid;
    25. }
    26. @Override
    27. public Mono writeWith(org.reactivestreams.Publisher body) {
    28. // if (getStatusCode().is2xxSuccessful()) {
    29. // //正常情况直接返回
    30. // return super.writeWith(body);
    31. // } else
    32. if (body instanceof Flux) {
    33. //异常情况保存响应
    34. Fluxextends DataBuffer> fluxBody = Flux.from(body);
    35. return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
    36. DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
    37. DataBuffer join = dataBufferFactory.join(dataBuffers);
    38. byte[] content = new byte[join.readableByteCount()];
    39. join.read(content);
    40. DataBufferUtils.release(join);
    41. String responseBody = new String(content, StandardCharsets.UTF_8);
    42. log.info("response body: {}", responseBody);
    43. LogCacheMap.saveResponse(uuid, responseBody);
    44. byte[] uppedContent = responseBody.replaceAll(":null", ":\"\"").getBytes(StandardCharsets.UTF_8);
    45. return bufferFactory.wrap(uppedContent);
    46. }
    47. ));
    48. }
    49. return super.writeWith(body);
    50. }
    51. }

     用到的自定义工具类

    1. package com.chilun.apiopenspace.gateway.Utils;
    2. import java.util.HashMap;
    3. /**
    4. * @author 齿轮
    5. * @date 2024-02-29-18:52
    6. */
    7. public class LogCacheMap {
    8. public static HashMap LogMap = new HashMap<>();
    9. public static void saveRequest(String uuid, String request) {
    10. LogMap.put(uuid + "request", request);
    11. }
    12. public static String getRequest(String uuid) {
    13. return LogMap.remove(uuid + "request");
    14. }
    15. public static void saveResponse(String uuid, String response) {
    16. LogMap.put(uuid + "response", response);
    17. }
    18. public static String getResponse(String uuid) {
    19. return LogMap.remove(uuid + "response");
    20. }
    21. }

    全局过滤器

    1. package com.chilun.apiopenspace.gateway.filter;
    2. import com.chilun.apiopenspace.gateway.Utils.LogCacheMap;
    3. import com.chilun.apiopenspace.gateway.service.AccessLogService;
    4. import com.google.common.base.Joiner;
    5. import lombok.extern.slf4j.Slf4j;
    6. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    7. import org.springframework.cloud.gateway.filter.GlobalFilter;
    8. import org.springframework.core.Ordered;
    9. import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
    10. import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
    11. import org.springframework.stereotype.Component;
    12. import org.springframework.web.server.ServerWebExchange;
    13. import reactor.core.publisher.Mono;
    14. import javax.annotation.Resource;
    15. import java.util.UUID;
    16. /**
    17. * @author 齿轮
    18. * @date 2024-02-28-14:35
    19. */
    20. @Slf4j
    21. @Component
    22. public class LogFilter implements GlobalFilter, Ordered {
    23. @Resource
    24. AccessLogService logService;
    25. @Override
    26. public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    27. String uuid = UUID.randomUUID().toString();
    28. //注入requestDecorator、responseDecorator用于获得请求体、响应体
    29. ServerHttpRequestDecorator requestDecorator = new LoggingRequestDecorator(exchange.getRequest(), exchange, uuid);
    30. ServerHttpResponseDecorator responseDecorator = new LoggingResponseDecorator(exchange.getResponse(), uuid);
    31. return chain.filter(exchange.mutate().request(requestDecorator).response(responseDecorator).build()).then(Mono.just(exchange))
    32. .map(serverWebExchange -> {
    33. if (serverWebExchange.getResponse().getStatusCode().is2xxSuccessful()) {
    34. logService.sendCommonLog(true);
    35. logService.sendRightLog(LogCacheMap.getRequest(uuid), LogCacheMap.getResponse(uuid));
    36. } else {
    37. logService.sendCommonLog(false);
    38. logService.sendErrorLog(LogCacheMap.getRequest(uuid), LogCacheMap.getResponse(uuid));
    39. }
    40. return serverWebExchange;
    41. })
    42. .then();
    43. }
    44. @Override
    45. public int getOrder() {
    46. return Ordered.HIGHEST_PRECEDENCE;
    47. }
    48. }

    如果也是使用Map存储请求体,注意用不到请求体/响应体后删除他们,避免内存溢出。

  • 相关阅读:
    目标检测新SOTA:YOLOv9 问世,新架构让传统卷积重焕生机
    [Q&A]AttributeError: module ‘signal‘ has no attribute ‘SIGALRM‘
    华为云云耀云服务器L实例评测 | 基于docker部署nacos2.2.3服务
    windows_tcp简单代码
    Linux--inode
    非线性方程求根方法总结——(从二分法、试位法到牛顿迭代、弦截法、二次插值等)
    架构师成长之路|Redis实现延迟队列的三种方式
    NetHTTPClient访问https网站出错。
    C++,STL(补)vector底层实现、动态数组
    【滤波跟踪】基于北方苍鹰和粒子群算法优化粒子滤波器实现目标滤波跟踪附matlab代码
  • 原文地址:https://blog.csdn.net/lifetime_gear/article/details/136379521