springcloudgateway⽇志打印
从api请求中获取访问的具体信息,是⼀个很常见的功能,这⼏天在研究springcloud,使⽤到了其中的gateway,刚好将研究的过程结果都记录下来
0. Version
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<spring-cloud.version>Greenwich.M3</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
1. GET请求
对于记录get的请求,gateway中过滤器的Request().getQueryParams()⽅法就可以获取的到了,关键的代码如下
// 记录请求的参数信息针对GET 请求
MultiValueMap<String, String> queryParams = QueryParams();
for (Map.Entry<String, List<String>> entry : Set()) {
builder.Key()).append("=").append(StringUtils.Value(), ",")).append(",");
}
2. POST请求
对于将请求的参数,存放在body这类的请求(如post),⽹上的很多⽅法是从ServerHttpRequest对象的getBody()⽅法返回的Flux<DataBuffer>进⾏读取的,依靠响应式编程来进⾏读取,但在⾃⼰demo中都
没有办法真正获取到
在参考⼀遍⽹友的⽂章后,可以参照ModifyRequestBodyGatewayFilterFactory提供的类的做法来进⾏,⾃⼰的实现,需要注意的是因为从body中读取出来的内容,是依靠响应式编程的,也就是subscribe()被调⽤过⼀次后,不能被springboot内部再调⽤⼀次,所以我们需要重新返回⼀个新的request回去,以下是⽐较核⼼的代码
/**
* 过滤器的内部类
*/
private class InnerFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取⽤户传来的数据类型
MediaType mediaType = Request().getHeaders().getContentType();
ServerRequest serverRequest = new DefaultServerRequest(exchange);
// 如果是json格式,将body内容转化为object or map 都可
if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)){
Mono<Object> modifiedBody = serverRequest.bodyToMono(Object.class)
.flatMap(body -> {
Request(), body);
return Mono.just(body);
});
return getVoidMono(exchange, chain, Object.class, modifiedBody);
}
/
/ 如果是表单请求
else if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType)){
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
// .log("modify_request_mono", Level.INFO)
.flatMap(body -> {
Request(), body);
return Mono.just(body);
});
return getVoidMono(exchange, chain, String.class, modifiedBody);
}
springcloud和springboot// TODO 这⾥未来还可以限制⼀些格式
/
/ ⽆法兼容的请求,则不读取body,像Get请求这种
Request(), "");
return chain.filter(exchange.mutate().Request()).build());
}
/**
* 优先级默认设置为最⾼
* @return
*/
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
/**
* 参照 ModifyRequestBodyGatewayFilterFactory.java 截取的⽅法
* @param exchange
* @param chain
* @param outClass
* @param modifiedBody
* @return
*/
private Mono<Void> getVoidMono(ServerWebExchange exchange, GatewayFilterChain chain, Class outClass, Mono<?> modifiedBody) { BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass);
HttpHeaders headers = new HttpHeaders();
headers.Request().getHeaders());
// the new content type will be computed by bodyInserter
// and then set in the request decorator
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext())
// .log("modify_request", Level.INFO)
.then(Mono.defer(() -> {
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(
@Override
public HttpHeaders getHeaders() {
long contentLength = ContentLength();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.Headers());
if (contentLength > 0) {
httpHeaders.setContentLength(contentLength);
} else {
// TODO: this causes a 'HTTP/1.1 411 Length Required'
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
}
return httpHeaders;
}
@Override
public Flux<DataBuffer> getBody() {
Body();
}
};
return chain.filter(exchange.mutate().request(decorator).build());
}));
}
/**
* 记录到请求⽇志中去
* @param request request
* @param body 请求的body内容
*/
private void recordLog(ServerHttpRequest request, Object body) {
// 记录要访问的url
StringBuilder builder = new StringBuilder(" request url: ");
builder.URI().getRawPath());
// 记录访问的⽅法
HttpMethod method = Method();
if (null != method){
builder.append(", method: ").append(method.name());
}
// 记录头部信息
builder.append(", header { ");
for (Map.Entry<String, List<String>> entry : Headers().entrySet()) {
builder.Key()).append(":").append(StringUtils.Value(), ",")).append(",");
}
// 记录参数
builder.append("} param: ");
// 处理get的请求
if (null != method && HttpMethod.GET.matches(method.name())) {
/
/ 记录请求的参数信息针对GET 请求
MultiValueMap<String, String> queryParams = QueryParams();
for (Map.Entry<String, List<String>> entry : Set()) {
builder.Key()).append("=").append(StringUtils.Value(), ",")).append(",");
}
}
else {
// 从body中读取参数
builder.append(body);
}
LogUtil.String());
}
}
关于项⽬的完整代码,在我的上
运⾏情况如下
在⽇志中的打印为
2019-06-01 16:47:30.442 [reactor-http-nio-2] INFO - request url: /open/check, method: POST, header { Accept:/,Content-type:application/json,User-Agent:curl/7.58.0,Host:localhost:8888,Content-Length:68,} param: {name=zhangsan, address=3678921789378217397128973982189321}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论