spring cloud gateway中读取请求参数

1. 我的版本:

  • spring-cloud:Hoxton.RELEASE

  • spring-boot:2.2.2.RELEASE

  • spring-cloud-starter-gateway

2. 请求日志

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author MinWeikai
 * @date 2019-12-20 18:09:39
 */
@Slf4j
@Component
public class LoggerFilter implements GlobalFilter {

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpRequest request = exchange.getRequest();
		String method = request.getMethodValue();

		if (HttpMethod.POST.matches(method)) {
			return DataBufferUtils.join(exchange.getRequest().getBody())
					.flatMap(dataBuffer -> {
						byte[] bytes = new byte[dataBuffer.readableByteCount()];
						dataBuffer.read(bytes);
						String bodyString = new String(bytes, StandardCharsets.UTF_8);
						logtrace(exchange, bodyString);
						exchange.getAttributes().put("POST_BODY", bodyString);
						DataBufferUtils.release(dataBuffer);
						Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
							DataBuffer buffer = exchange.getResponse().bufferFactory()
									.wrap(bytes);
							return Mono.just(buffer);
						});

						ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
								exchange.getRequest()) {
							@Override
							public Flux<DataBuffer> getBody() {
								return cachedFlux;
							}
						};
						return chain.filter(exchange.mutate().request(mutatedRequest)
								.build());
					});
		} else if (HttpMethod.GET.matches(method)) {
			Map m = request.getQueryParams();
			logtrace(exchange, m.toString());
		}
		return chain.filter(exchange);
	}

	/**
	 * 日志信息
	 *
	 * @param exchange
	 * @param param    请求参数
	 */
	private void logtrace(ServerWebExchange exchange, String param) {
		ServerHttpRequest serverHttpRequest = exchange.getRequest();
		String path = serverHttpRequest.getURI().getPath();
		String method = serverHttpRequest.getMethodValue();
		String headers = serverHttpRequest.getHeaders().entrySet()
				.stream()
				.map(entry -> "            " + entry.getKey() + ": [" + String.join(";", entry.getValue()) + "]")
				.collect(Collectors.joining("\n"));
		log.info("\n" + "----------------             ----------------             ---------------->>\n" +
						"HttpMethod : {}\n" +
						"Uri        : {}\n" +
						"Param      : {}\n" +
						"Headers    : \n" +
						"{}\n" +
						"\"<<----------------             ----------------             ----------------"
				, method, path, param, headers);
	}

}

3. 测试输出,我这边测试没有问题,日志正常输出

我的代码应用示例项目:微服务项目实战练习: 结合现在流行的技术框架构建springcloud微服务组件+nacos+seata项目Demo;如果是新手刚接触这些项目组件,可pull此项目用于学习!https://gitee.com/mwk719/microservice_practice

### 如何在 Spring Cloud Gateway拦截读取 HTTP 响应参数 为了实现对响应数据的操作,在 Spring Cloud Gateway 中可以利用 `GlobalFilter` 或者自定义的 `GatewayFilter` 来处理。下面展示的是通过创建一个全局过滤器来捕获并打印所有的响应体内容的方法。 #### 创建 Global Filter 实现类 首先,需要编写一个新的 Java 类继承于 `Ordered` 接口,并重写其方法以便能够控制该过滤器执行顺序;同时也要覆盖 `filter()` 方法用于实际逻辑操作: ```java 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.ServerHttpResponse; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; public class ResponseReadFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpResponse originalResponse = exchange.getResponse(); // 自定义 DataBufferFactory 用来保存原始的数据缓冲区工厂对象 DataBufferFactory bufferFactory = originalResponse.bufferFactory(); // 将原生 response 替换为我们的装饰版本 ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { if (body instanceof Flux) { Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body; // 复制一份副本供后续使用 return super.writeWith(fluxBody.map(dataBuffer -> { byte[] content = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(content); // 构建新的DataBuffer实例存储修改后的字节数组 DataBufferUtils.release(dataBuffer); // 释放旧buffer String responseBodyStr = new String(content, StandardCharsets.UTF_8); System.out.println("response Body:" + responseBodyStr); // 返回新构建好的dataBuffer给下游继续流转 return bufferFactory.wrap(content); })); } // 如果不是flux类型的publisher,则直接返回父级调用的结果 return super.writeWith(body); } }; // 使用替换过的decoratedResponse替代原来的originalResponse参与整个流程 return chain.filter(exchange.mutate().response(decoratedResponse).build()); } @Override public int getOrder() { return -1; // 设置优先级,越低越先被执行 } } ``` 这段代码实现了对所有经过此网关的应用程序发出的HTTP响应消息中的主体部分进行监听的功能[^2]。每当有响应流出时都会触发上述逻辑,从而允许开发者在此处加入任何想要完成的任务,比如日志记录、性能监控或是其他业务需求相关的处理工作。 需要注意的一点是在多线程环境下可能会遇到并发访问的问题,因此对于共享资源应当采取适当措施加以保护以免造成竞争条件等问题的发生。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值