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. 关于BenchMark/c++11计时器/Chrome:tracing 的一些笔记

    A benchmark is a test of the performance of a computer system. ​ 基准测试是对计算机系统的性能的测试 计时器 性能的指标就是时间,在c+ ...

  2. Git (常用命令)

    某程序猿退休后决定练习书法,于是花重金买下文房四宝.某日,饭后突生雅兴,一番磨墨拟纸 并点上上好檀香.定神片刻,泼墨挥毫,郑重地写下一行:Hello World 斯~ 有被冷到吗哈哈哈 Git常用命令 ...

  3. 团队Beta5

    队名:观光队 链接 组长博客 作业博客 组员实践情况 王耀鑫 **过去两天完成了哪些任务 ** 文字/口头描述 学习 展示GitHub当日代码/文档签入记录 无 接下来的计划 无 **还剩下哪些任务 ...

  4. CentOS 并没有死,Rocky Linux 让其重生

    点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 近日,CentOS 官方发文称CentOS Stream ...

  5. OpenStack 安装 Keystone

    OpenStack 安装 Keystone 本篇主要记录一下 如何安装 openstack的 第一个组件 keystone 认证授权组件 openstack 版本 我选的是queens 版本 1.Op ...

  6. 图解Dijkstra(迪杰斯特拉)算法+代码实现

    简介 Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径.主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止.Dijkstra算法是很有代表性的 ...

  7. Mybatis-Plus乐观锁Version

    实现原理 取出记录时,获取当前version更新时,带上这个version执行更新时, set version = newVersion where version = oldVersion如果ver ...

  8. 120_PowerBI堆积瀑布图_R脚本Visual

    博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.效果 二.data 三.添加字段 注意红色框标注地方 四.code # 下面用于创建数据帧并删除重复行的代码始终执行, ...

  9. WTF表单验证

    WTF表单验证可分为3个步骤: ①导入wtf扩展提供的表单验证器.(from wtforms.validators import DataRequired,EqualTo) ②定义表单类 # 定义表单 ...

  10. 个人冲刺(六)——体温上报app(一阶段)

    任务:完成了自动获取定位信息以及自动获取时间功能 自动获取定位信息 public void onReceiveLocation(BDLocation location){ //此处的BDLocatio ...