java getway springcloud 记录请求数据,兼容post请求无参数和response返回无参数

方式1

import com.icar.web.icarutils.util.ClientUtil;
import com.icar.web.icarutils.util.IdWorkerUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
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.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.stream.Collectors; @Component
@Slf4j
public class HttpRequestGlobalFilter implements GlobalFilter, Ordered { @Value("${xxxx.collectrequestlogs:false}")
private Boolean collectrequestlog;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String accessId=new IdWorkerUtil().nextId()+"";
try{
String method = request.getMethodValue();
String contentType = request.getHeaders().getFirst("Content-Type"); if ("POST".equals(method)&&(contentType!=null&&contentType.equals(MediaType.APPLICATION_JSON_VALUE))){ //&& contentType.startsWith("multipart/form-data")
if(collectrequestlog){
return SavePostRequestDataBody(exchange, chain,request,method,contentType,accessId);
}
else {
SaveLogData(exchange,"",accessId);
}
}
else if ("GET".equals(method)) {
Map requestQueryParams = request.getQueryParams();
String param=requestQueryParams.toString();
SaveLogData(exchange,param,accessId);
}else{
SaveLogData(exchange,"",accessId);
}
ServerHttpRequest.Builder requestBuilder = request.mutate();
//requestBuilder.build().getHeaders().set("userId",userId);
requestBuilder.headers(k -> k.set("accessId", accessId));
ServerHttpRequest builder = requestBuilder.build();
return chain.filter(exchange.mutate().request(builder.mutate().build()).build());
}
catch (Exception e){
log.error("",e);
}
ServerHttpRequest.Builder requestBuilder = request.mutate();
//requestBuilder.build().getHeaders().set("userId",userId);
requestBuilder.headers(k -> k.set("accessId", accessId));
ServerHttpRequest builder = requestBuilder.build();
return chain.filter(exchange.mutate().request(builder.mutate().build()).build());
} /**
* 获取post请求数据
* @param exchange
* @param method
* @param contentType
* @param accessId
* @return
*/
private Mono<Void> SavePostRequestDataBody(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request, String method, String contentType, String accessId) {
//判断请求是否有参数
HttpHeaders headers = request.getHeaders();
long contentLength = headers.getContentLength();
//当请求体里面没有任何数据的话不用后面的获取数据步骤
if (contentLength < 1) {
SaveLogData(exchange,"",accessId);
ServerHttpRequest.Builder requestBuilder = request.mutate();
//requestBuilder.build().getHeaders().set("userId",userId);
requestBuilder.headers(k -> k.set("accessId", accessId));
ServerHttpRequest builder = requestBuilder.build();
return chain.filter(exchange.mutate().request(builder.mutate().build()).build());
}
Flux<DataBuffer> flux =exchange.getRequest().getBody();
Mono<Void> mono= DataBufferUtils.join(flux)
.flatMap(dataBuffer -> { try
{
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes); try {
if(contentType==null||!contentType.startsWith("application/json")){ //multipart/form-data
SaveLogData(exchange,"",accessId);
}else{
String bodyString = new String(bytes, "utf-8");
SaveLogData(exchange,bodyString,accessId);
} //log.info(bodyString);
//exchange.getAttributes().put("POST_BODY",bodyString);
} catch (UnsupportedEncodingException e) {
log.error("",e);
}
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;
}
};
ServerHttpRequest.Builder requestBuilder = mutatedRequest.mutate();
requestBuilder.headers(k -> k.set("accessId", accessId));
ServerHttpRequest builder = requestBuilder.build(); return chain.filter(exchange.mutate().request(mutatedRequest)
.build());
}
catch (Exception e){
SaveLogData(exchange,"",accessId);
log.error("",e);
}finally { }
return null;
});
return mono;
} private void SaveLogData(ServerWebExchange exchange,String param,String accessId) {
try{
ServerHttpRequest request= exchange.getRequest();
String ip = ClientUtil.getIPAddress(request);
String method = request.getMethodValue();
String url = request.getURI().toString();
String headers = request.getHeaders().entrySet()
.stream()
.map(entry -> " " + entry.getKey() + ": [" + String.join(";", entry.getValue()) + "]")
.collect(Collectors.joining("\n"));
log.info("\n" + "-------------------------------------------------------------------------------->>\n" +
"locationtype: request\n" +
"Url: {}\n" +
"HttpMethod: {}\n" +
"IP: {}\n" +
"accessId: {}\n" +
"Param: {}\n" +
"Headers: \n" +
"{}\n" +
"\"<<--------------------------------------------------------------------------------"
, method, url, ip,accessId,param, headers); }
catch (Exception e){
log.error("",e);
}
} @Override
public int getOrder() {
return -200;
}
}

方式二

import lombok.Data;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; /**
* 网关上下文
*/
@Data
public class GatewayContext { public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext"; /**
* cache headers
*/
private HttpHeaders headers; /**
* baseHeader
*/
private HttpHeaders baseHeader; /**
* cache json body
*/
private String cacheBody;
/**
* cache formdata
*/
private MultiValueMap<String, String> formData = new LinkedMultiValueMap<>(); /**
* ipAddress
*/
private String ipAddress; /**
* path
*/
private String path; }
import com.icar.web.gateway.entity.GatewayContext;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map; /**
* 请求内容存储 处理请求内容 内容放在gatewayContext中
*//*
* @author kam
*
* <p>
* 请求内容存储 处理请求内容 内容放在gatewayContext中
* </p>
*/ @Component
@Slf4j
public class RequestCoverFilter implements GlobalFilter, Ordered { /**
* default HttpMessageReader
*/ private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders(); /* * ReadFormData
*
* @param exchange
* @param chain
* @return
*/ private Mono<Void> readFormData(ServerWebExchange exchange, GatewayFilterChain chain,
GatewayContext gatewayContext) {
final ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders(); return exchange.getFormData().doOnNext(multiValueMap -> {
gatewayContext.setFormData(multiValueMap);
log.debug("[GatewayContext]Read FormData:{}", multiValueMap);
}).then(Mono.defer(() -> {
Charset charset = headers.getContentType().getCharset();
charset = charset == null ? StandardCharsets.UTF_8 : charset;
String charsetName = charset.name();
MultiValueMap<String, String> formData = gatewayContext.getFormData(); /**
* formData is empty just return
*/ if (null == formData || formData.isEmpty()) {
return chain.filter(exchange);
}
StringBuilder formDataBodyBuilder = new StringBuilder();
String entryKey;
List<String> entryValue;
try {
/**
* repackage form data
*/ for (Map.Entry<String, List<String>> entry : formData.entrySet()) {
entryKey = entry.getKey();
entryValue = entry.getValue();
if (entryValue.size() > 1) {
for (String value : entryValue) {
formDataBodyBuilder.append(entryKey).append("=")
.append(URLEncoder.encode(value, charsetName)).append("&");
}
} else {
formDataBodyBuilder.append(entryKey).append("=")
.append(URLEncoder.encode(entryValue.get(0), charsetName)).append("&");
}
}
} catch (UnsupportedEncodingException e) {
// ignore URLEncode Exception
} /**
* substring with the last char '&'
*/ String formDataBodyString = "";
if (formDataBodyBuilder.length() > 0) {
formDataBodyString = formDataBodyBuilder.substring(0, formDataBodyBuilder.length() - 1);
}
/**
* get data bytes
*/ byte[] bodyBytes = formDataBodyString.getBytes(charset);
int contentLength = bodyBytes.length;
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(request) { /**
* change content-length
*
* @return
*/ @Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(super.getHeaders());
if (contentLength > 0) {
httpHeaders.setContentLength(contentLength);
} else {
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
}
return httpHeaders;
}
/**
* read bytes to Flux<Databuffer>
*
* @return
*/ @Override
public Flux<DataBuffer> getBody() {
return DataBufferUtils.read(new ByteArrayResource(bodyBytes),
new NettyDataBufferFactory(ByteBufAllocator.DEFAULT), contentLength);
}
};
ServerWebExchange mutateExchange = exchange.mutate().request(decorator).build();
log.info("[GatewayContext]Rewrite Form Data :{}", formDataBodyString); return chain.filter(mutateExchange);
}));
} /**
* ReadJsonBody
*
* @param exchange
* @param chain
* @return
*/ private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain, GatewayContext gatewayContext) { /**
* join the body
*/ return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> { /*
* read the body Flux<DataBuffer>, and release the buffer
* //TODO when SpringCloudGateway Version Release To G.SR2,this can be update with the new version's feature
* see PR https://github.com/spring-cloud/spring-cloud-gateway/pull/1095
*/ byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
DataBufferUtils.retain(buffer);
return Mono.just(buffer);
});
/**
* repackage ServerHttpRequest
*/ ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
/**
* mutate exchage with new ServerHttpRequest
*/ ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build(); /**
* read body string with default messageReaders
*/ return ServerRequest.create(mutatedExchange, messageReaders).bodyToMono(String.class)
.doOnNext(objectValue -> {
gatewayContext.setCacheBody(objectValue);
log.debug("[GatewayContext]Read JsonBody:{}", objectValue);
}).then(chain.filter(mutatedExchange));
});
} @Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
} @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { /**
* save request path and serviceId into gateway context
*/ ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse(); GatewayContext gatewayContext = new GatewayContext();
String path = request.getPath().pathWithinApplication().value();
gatewayContext.setPath(path);
gatewayContext.getFormData().addAll(request.getQueryParams());
gatewayContext.setIpAddress(String.valueOf(request.getRemoteAddress()));
HttpHeaders headers = request.getHeaders();
gatewayContext.setHeaders(headers);
log.debug("HttpMethod:{},Url:{}", request.getMethod(), request.getURI().getRawPath()); /// 注意,因为webflux的响应式编程 不能再采取原先的编码方式 即应该先将gatewayContext放入exchange中,否则其他地方可能取不到 /**
* save gateway context into exchange
*/ exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT, gatewayContext); // 处理参数
MediaType contentType = headers.getContentType();
long contentLength = headers.getContentLength();
if (contentLength > 0) {
if (MediaType.APPLICATION_JSON.equals(contentType) || MediaType.APPLICATION_JSON_UTF8.equals(contentType)) {
return readBody(exchange, chain, gatewayContext);
}
if (MediaType.APPLICATION_FORM_URLENCODED.equals(contentType)) {
return readFormData(exchange, chain, gatewayContext);
}
}
// TODO 多版本划区域控制后期实现 log.debug("[GatewayContext]ContentType:{},Gateway context is set with {}", contentType, gatewayContext);
return chain.filter(exchange);
} }
spring-cloud的版本
    <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

参考原来

pringCloud-Gateway获取body参数,解决只能获取一次问题,终极解决方案

java getway springcloud 记录请求数据的更多相关文章

  1. spring mvc 通过拦截器记录请求数据和响应数据

    spring mvc 能过拦截器记录请求数据记录有很多种方式,主要有以下三种: 1:过滤器 2:HandlerInterceptor拦截器 3:Aspect接口控制器 但是就我个人所知要记录返回的数据 ...

  2. 借助 AOP 为 Java Web 应用记录性能数据

    作为开发者,应用的性能始终是我们最感兴趣的话题之一.然而,不是所有的开发者都对自己维护的应用的性能有所了解,更别说快速定位性能瓶颈并实施解决方案了. 今年北京 Velocity 的赞助商大多从事 AP ...

  3. ASP.NET Web API 记录请求响应数据到日志的一个方法

    原文:http://blog.bossma.cn/dotnet/asp-net-web-api-log-request-response/ ASP.NET Web API 记录请求响应数据到日志的一个 ...

  4. Java生鲜电商平台-SpringCloud分布式请求跟踪系统设计与实践

    Java生鲜电商平台-SpringCloud分布式请求跟踪系统设计与实践 Java生鲜电商平台微服务现状 某个服务挂了,导致上游大量报警,如何快速定位哪个服务出问题? 某个核心挂了,导致大量报错,如何 ...

  5. Java服务器对外提供接口以及Android端向服务器请求数据

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/5056780.html 讲解下java服务器是如何对移动终端提供接口的,以什么数据格式提供出去,移动端又是怎么 ...

  6. java发送post请求 ,请求数据放到body里

    java利用httpclient发送post请求 ,请求数据放到body里. /** * post请求 ,请求数据放到body里 * * @author lifq * * 2017年3月15日 下午3 ...

  7. SpringAop实操之记录关键业务请求数据

    AOP,中文名称,切面.在不影响业务代码情况下,实现想要的功能,是个真炫酷的事. aop是个好东西,记录日志是必须的. 记录数据也一样的,那么也是可以用aop来实现的,这里借助注解一起解决问题吧. 因 ...

  8. Android(或者Java)通过HttpUrlConnection向SpringMVC请求数据(数据绑定)

    问题描写叙述 当我们使用SpringMVC作为服务端的框架时,有时不仅仅要应对web前端(jsp.javascript.Jquery等)的訪问请求,有时还可能须要响应Android和JavaSE(桌面 ...

  9. 接口测试时遇到 java 代码加密请求数据,用 python 的我该怎么办?

    前言 自动化测试应用越来越多了,尤其是接口自动化测试. 在接口测试数据传递方面,很多公司都会选择对请求数据进行加密处理. 而目前为主,大部分公司的产品都是java语言实现的.所以加密处理也是java实 ...

随机推荐

  1. 干货|Linux平台搭建网关服务器

    概述 集群中一共10台服务器组成了局域网环境,但其中只有一台有外网网卡可以访问互联网.现要求另外9台服务器通过这台主机进行互联网访问.  实验环境介绍 利用iptables搭建网关服务器,即通过SNA ...

  2. 面试题|Docker的优缺点

    开源Linux 长按二维码加关注~ 上一篇:Linux中几个正则表达式的用法 Docker解决的问题: 由于不同的机器有不同的操作系统,以及不同的库和组件,在将一个应用部署到多台机器上需要进行大量的环 ...

  3. 看 AWS 如何通过 Nitro System 构建竞争优势

    目录 目录 目录 前言 Amazon Nitro System Overview AWS EC2 的虚拟化技术演进之路 Nitro Hypervisor Nitro Cards Nitro Contr ...

  4. 【mq】从零开始实现 mq-06-消费者心跳检测 heartbeat

    前景回顾 [mq]从零开始实现 mq-01-生产者.消费者启动 [mq]从零开始实现 mq-02-如何实现生产者调用消费者? [mq]从零开始实现 mq-03-引入 broker 中间人 [mq]从零 ...

  5. Python-100-Days-master

    跟着python100学习一下 100以内的素数 # 输出100以内的所有素数 # 想法:从1到100遍历,假设得到了i=17,那么此时从1到9遍历,如果找到了一个数用17能除尽则跳出循环 # 如果找 ...

  6. salesforce零基础学习(一百一十三)Trigger中获取IP地址的过程

    本篇参考: https://developer.salesforce.com/docs/atlas.en-us.228.0.apexcode.meta/apexcode/apex_class_Auth ...

  7. 3.Docker常用命令

    帮助启动类命令 启动docker: systemctl start docker 停止docker: systemctl stop docker 重启docker: systemctl restart ...

  8. 我用13行摆烂了你的oj4

    13行代码AC oj4是怎么回事呢?13行代码AC oj4相信大家都很熟悉,但是13行代码AC oj4是怎么回事呢,下面就让小编带大家一起了解吧.13行代码AC oj4,其实就是13行代码AC oj4 ...

  9. HCNP Routing&Switching之链路聚合

    前文我们了解了MSTP相关话题,回顾清参考https://www.cnblogs.com/qiuhom-1874/p/16268682.html:今天我们来聊一聊链路聚合相关话题: 链路聚合是链路高可 ...

  10. 由C# dynamic是否装箱引发的思考

    前言 前几天在技术群里看到有同学在讨论关于dynamic是否会存在装箱拆箱的问题,我当时第一想法是"会".至于为啥会有很多人有这种疑问,主要是因为觉得dynamic可能是因为有点特 ...