首先要在网关项目中,新增一个全局过滤器,因为获取请求参数的时,如果不加处理,获取一次后,后面的过滤器就拿不到请求参数了,我理解别人大概试着意思.
package com.enterprise.filter;
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.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;
/**
* @author: Blossom
* CacheBodyGlobalFilterk的作用是为了解决
* ServerHttpRequest中body的数据为NULL的情况
*/
@Component
public class CacheBodyGlobalFilter implements Ordered, GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (exchange.getRequest().getHeaders().getContentType() == null) {
return chain.filter(exchange);
} else {
//获取databuffer
return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> { //设定返回值并处理
DataBufferUtils.retain(dataBuffer); //设定存储空间
Flux<DataBuffer> cachedFlux = Flux//读取Flux中所有数据并且保存
.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator( //得到ServerHttpRequest
exchange.getRequest()) {
@Override //重载getBody方法 让其从我设定的缓存获取
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
//放行 并且设定exchange为我重载后的
return chain.filter(exchange.mutate().request(mutatedRequest).build());
});
}
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
在建一个过滤器,保存访问日志信息,通过Feign 调用其他模块的保存接口
package com.enterprise.filter;
import com.alibaba.fastjson.JSON;
import com.enterprise.feignclient.IFeignSystemService;
import com.enterprise.utils.IpUtil;
import com.nimbusds.jose.JWSObject;
import io.netty.buffer.ByteBufAllocator;
import io.netty.util.CharsetUtil;
import net.minidev.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.beans.factory.annotation.Autowired;
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.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import javax.annotation.Resource;
import java.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
/**
* 保存访问日志
*/
@Component
public class AccessLogFilter implements GlobalFilter, Ordered {
@Autowired
private IFeignSystemService systemService;
@Resource
private RedisTemplate<String, Object> redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 请求对象
ServerHttpRequest request = exchange.getRequest();
// 响应对象
ServerHttpResponse response = exchange.getResponse();
String ip = IpUtil.getIP(request);
// 获取token
String authorization = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
String token = StringUtils.substringAfter(authorization, "Bearer ");
Map value = null;
if(StringUtils.isNotBlank(token)){
JWSObject jwsObject = null;
try {
jwsObject = JWSObject.parse(token);
} catch (ParseException e) {
e.printStackTrace();
}
JSONObject jsonObject = jwsObject.getPayload().toJSONObject();
String u = (String)redisTemplate.opsForValue().get("loginUser:"+jsonObject.get("jti").toString());
value = (Map) JSON.parse(u);
System.out.println(value);
}
RequestPath path = request.getPath();
if(StringUtils.startsWith(path.toString(),"/system/accessLog/list")){
//查看访问日志不记录日志
return chain.filter(exchange);
}
String parameter="";
if (HttpMethod.POST.equals(exchange.getRequest().getMethod()) && null != exchange.getRequest().getHeaders().getContentType()
&& exchange.getRequest().getHeaders().getContentType().includes(MediaType.APPLICATION_JSON)
&& !exchange.getRequest().getHeaders().getContentType().includes(MediaType.MULTIPART_FORM_DATA)) {
String requestbody = resolveBodyFromRequest(exchange.getRequest());
parameter = requestbody;
//return chain.filter(exchange.mutate().request(generateNewRequest(exchange.getRequest(), requestbody)).build());
}else if(HttpMethod.GET.equals(exchange.getRequest().getMethod())){
MultiValueMap<String, String> queryParams = request.getQueryParams();
parameter = queryParams.toString();
}
Map<String,String> log=new HashMap<>();
log.put("userId",value!=null?(String)value.get("id"):"");
log.put("userUsername",value!=null?(String)value.get("username"):"");
log.put("ip",ip);
log.put("path",path.toString());
log.put("method",exchange.getRequest().getMethod().toString());
log.put("reqParameter",parameter);
//saveLog(log);
//return chain.filter(exchange);
return chain.filter(exchange.mutate().response(recordResponseLog(exchange,log)).build());
}
/*private void saveLog(Map<String, String> log) {
}*/
private void saveLog(Map map){
System.out.println(map);
systemService.saveLog(map);
}
/**
* 这里必须小于-1
* @return
*/
@Override
public int getOrder() {
return -2;
}
/**
* 获取响应数据
* @param exchange
* @return
*/
private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange,Map map) {
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = exchange.getRequest().getHeaders();
MediaType mediaType = headers.getContentType();
DataBufferFactory bufferFactory = response.bufferFactory();
ServerHttpResponseDecorator decoratorResponse = new ServerHttpResponseDecorator(response) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
// 没有token的不会记录日志,所以不记录响应
/*if (StrUtil.isBlank(headers.getFirst("Authorization"))) {
return super.writeWith(body);
}*/
// 过滤上传附件请求
if ((mediaType != null && mediaType.equals(MediaType.MULTIPART_FORM_DATA))
|| (mediaType != null && mediaType.equals(MediaType.APPLICATION_FORM_URLENCODED))) {
return super.writeWith(body);
}
String path = (String)map.get("path");
if(StringUtils.startsWith(path,"/system/api/file")){
//下载文件
saveLog(map);
return super.writeWith(body);
}
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {// 解决返回体分段传输获取完整响应数据问题
StringBuilder bodyString = new StringBuilder();
dataBuffers.forEach(dataBuffer -> {
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
DataBufferUtils.release(dataBuffer);
bodyString.append(new String(content, CharsetUtil.UTF_8));
});
// 拿到返回数据,可以进行做一些修改
String result = bodyString.toString();
byte[] uppedContent = new String(result.getBytes(), CharsetUtil.UTF_8).getBytes();
// 保存响应日志
map.put("response",result);
saveLog(map);
response.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
}
return super.writeWith(body);
}
};
return decoratorResponse;
}
private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
//获取请求体
Flux<DataBuffer> body = serverHttpRequest.getBody();
AtomicReference<String> bodyRef = new AtomicReference<>();
body.subscribe(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
DataBufferUtils.release(buffer);
bodyRef.set(charBuffer.toString());
});
//获取request body
return bodyRef.get();
}
private ServerHttpRequest generateNewRequest(ServerHttpRequest request, String requestBody) {
URI ex = UriComponentsBuilder.fromUri(request.getURI()).build(true).toUri();
ServerHttpRequest newRequest = request.mutate().uri(ex).build();
DataBuffer dataBuffer = stringBuffer(requestBody);
Flux<DataBuffer> flux = Flux.just(dataBuffer);
newRequest = new ServerHttpRequestDecorator(newRequest) {
@Override
public Flux<DataBuffer> getBody() {
return flux;
}
};
return newRequest;
}
private DataBuffer stringBuffer(String value) {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
buffer.write(bytes);
return buffer;
}
}