新项目需要在getway统一做入参、出参加解密,记录日志。记录一下form,x-www-form-urlencoded , json 这几种修改数据的方式。 gateway做拦截器是实现GlobalFilter接口,修改json方式网上有很多文章,后来又想研究研究能不能实现修改form-data参数,以及文件请求,后者文章不多大部分是怎么读数据的教学。现在发一下我的实现方式。 使用的gateway版本是2.2.1.RELEASE cloud版本Greenwich.SR2
@Override
public Mono
Mono
ServerHttpRequest request = exchange.getRequest();
MediaType contentType = request.getHeaders().getContentType();
if (Objects.nonNull(contentType) && Objects.nonNull(exchange.getRequest().getMethod())
&& exchange.getRequest().getMethod().equals(HttpMethod.POST)) {
if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
// json 请求体处理
mono = this.transferBody(exchange, chain);
}else if(MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)){
// multipart/form-data处理
mono = this.fileRequest(contentType,exchange,chain);
}else if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)){
// x-www-form-urlencoded 格式处理
mono = this.xwFromBody(exchange,chain);
}
}else{
if(exchange.getRequest().getMethod().equals(HttpMethod.GET)){
Map
log.info("queryParams:{}", queryParams);
}
}
return mono;
}
修改json数据
/**
* 修改修改body参数
*/
private Mono
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
headers.remove(HttpHeaders.CONTENT_LENGTH);
MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers);
ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate();
requestBuilder.headers(k -> k.remove("Content-length"));
Mono mono = bodyInserter.insert(outputMessage, new BodyInserterContext())
.then(Mono.defer(() -> {
//解决body内数据过长读取不完整的问题
Flux
DataBufferHolder holder = new DataBufferHolder();
try{
body.subscribe(dataBuffer -> {
int len = dataBuffer.readableByteCount();
holder.length = len;
byte[] bytes = new byte[len];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
String oldBody = new String(bytes, StandardCharsets.UTF_8);
JsonNode jsonNode = objectMapper.readTree(in);
//到这可以读取数据,做校验之类的
//JsonNode token = oldDataJSON.get("token");
jsonNode .set("test","修改数据");
DataBuffer data = outputMessage.bufferFactory().allocateBuffer();
data.write(jsonNode.toString().getBytes(StandardCharsets.UTF_8));
holder.length = data.readableByteCount();
holder.dataBuffer=data;
});
}catch (Exception e){
if(e.getCause() instanceof ServiceException){
ServiceException e1 = (ServiceException) e.getCause();
return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(e1.getCode(), e1.getMessage())));
}
return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(SYSTEM_ERROR.getCode(), SYSTEM_ERROR.getMessage())));
}
ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer));
return chain.filter(exchange.mutate().request(decorator).build());
}));
return mono;
}
修改form表单参数,一般需要上传文件的请求用这个。数据读取都可以用json请求那个方法获取,但是带文件的请求用那个读了以后文件数据就变了,修改数据以后文件没法正常存储,所以按以下方式,直接读取字节然后拼接要改的数据
//修改form参数
private Mono
return DataBufferUtils.join(exchange.getRequest().getBody())
.flatMap(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
// new String(bytes);
//添加一些自定义参数,或者校验
String oldBody = addPara(contentType.toString(), new String(bytes));
byte[] bytes1 = oldBody.getBytes();
//这里截取数组是因为 form请求体数据末尾有--/r/n,这里需要截一段然后拼接自定义的数据。数据格式可以看文章末尾的链接
byte[] bytes2 = byteMerger(Arrays.copyOf(bytes,bytes.length-4), bytes1);
Flux
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes2);
DataBufferUtils.retain(buffer);
return Mono.just(buffer);
});
ServerHttpRequestDecorator mutatedRequest = newDecorator(exchange,bytes2.length,cachedFlux);
ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
return ServerRequest.create(mutatedExchange, MESSAGE_READERS)
.bodyToMono(byte[].class)
.then(chain.filter(mutatedExchange));
});
}
/**
* 修改form参数
* @param contentType 请求类型
* @param bodyString 请求body信息
*/
@SneakyThrows
public static String addPara(String contentType, String bodyString) {
StringBuffer stringBuffer = new StringBuffer();
String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9);//获取随机字符传信息
String boundary_end = StrUtil.format("--{}--\r\n", boundary);
Map
/**
*
* 根据自己需求进行对bodyString信息修改,例如下面,根据boundary对传入的bodyString进行了分割
* String[] split = bodyString.split(boundary);
* 然后将修改完后的信息封装到formMap中,需要注意的是,file文件需要以new FileResource(file, fileName)的形式当作value放到formMap中
*/
String part = "^\r\nContent-Disposition: form-data; name=\"([^/?]+)\"\r\n\r\n([^/?]+)\r\n--?$";
Pattern r = Pattern.compile(part);
String[] split = bodyString.split(boundary);
for(int x=1;x Matcher m = r.matcher(split[x]); if(m.find()){ String name = m.group(1); String value = m.group(2); System.out.println("name:"+name+" value:"+value); // formMap.put(name,value); } } formMap.put("test","添加自定义参数"); formMap.put("tcu",22222); Integer count =0; for (Map.Entry stringBuffer.append(appendPart(boundary, entry.getKey(), entry.getValue(),count)); count++; } stringBuffer.append(boundary_end);//拼接结束信息 log.info(stringBuffer.toString()); return stringBuffer.toString(); } 修改x-www-form-urlencoded参数 /** * 修改 x-www-form-urlencoded参数 * @param exchange * @param chain * @return */ private Mono ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); Mono BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); headers.remove(HttpHeaders.CONTENT_LENGTH); MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers); ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate(); requestBuilder.headers(k -> k.remove("Content-length")); return bodyInserter.insert(outputMessage, new BodyInserterContext()) .then(Mono.defer(() -> { Flux DataBufferHolder holder = new DataBufferHolder(); changeParamByXwForm(body,holder,outputMessage); ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer)); return chain.filter(exchange.mutate().request(decorator).build()); })); } //修改 x-www-form-urlencoded参数 private void changeParamByXwForm(Flux body.subscribe(dataBuffer -> { int len = dataBuffer.readableByteCount(); holder.length = len; byte[] bytes = new byte[len]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); String oldBody = new String(bytes, StandardCharsets.UTF_8); //直接拼接要改的数据就行 oldBody+="&tcu=123888"; DataBuffer data = outputMessage.bufferFactory().allocateBuffer(); data.write(oldBody.getBytes(StandardCharsets.UTF_8)); holder.length = data.readableByteCount(); holder.dataBuffer=data; }); } 修改请求参数完整代码 ReadAndChangeResFilter .java import cn.hutool.core.io.IORuntimeException; import cn.hutool.core.io.resource.MultiResource; import cn.hutool.core.io.resource.Resource; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.ContentType; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.Maps; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.support.BodyInserterContext; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.http.*; import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.BodyInserter; import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.server.HandlerStrategies; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.server.ServerWebExchange; import org.springframework.core.Ordered; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.byaero.utm.common.constant.CommonErrorCodeEnum.SYSTEM_ERROR; import static com.byaero.utm.common.constant.CommonErrorCodeEnum.TOKEN_NOT_EXISTENT_ERROR; @Slf4j @Component public class ReadAndChangeResFilter implements GlobalFilter, Ordered { private static final String CONTENT_DISPOSITION_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"\r\n\r\n"; private static final String CONTENT_DISPOSITION_FILE_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n"; private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary="; private static final String CONTENT_TYPE_FILE_TEMPLATE = "Content-Type: {}\r\n\r\n"; private final static String TOKEN_USERINFO_CACHE_FLAG = "TI-%s"; private static final List @Autowired private RedisUtil redisUtil; @Autowired private UserConvert userConvert; @Autowired private ObjectMapper objectMapper; @Autowired private UserManager userManager; @Override public Mono Mono ServerHttpRequest request = exchange.getRequest(); MediaType contentType = request.getHeaders().getContentType(); final GatewayContext gatewayContext = new GatewayContext(); // ServerWebExchangeUtils.putUriTemplateVariables(); if (Objects.nonNull(contentType) && Objects.nonNull(exchange.getRequest().getMethod()) && exchange.getRequest().getMethod().equals(HttpMethod.POST)) { if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) { // json 请求体处理 mono = this.transferBody(exchange, chain); }else if(MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)){ // multipart/form-data处理 mono = this.fileRequest(contentType,exchange,chain); }else if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)){ // x-www-form-urlencoded 格式处理 mono = this.xwFromBody(exchange,chain); } }else{ if(exchange.getRequest().getMethod().equals(HttpMethod.GET)){ Map log.info("queryParams:{}", queryParams); } } return mono; } //修改form参数 private Mono return DataBufferUtils.join(exchange.getRequest().getBody()) .flatMap(dataBuffer -> { byte[] bytes = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); String oldBody = addPara(contentType.toString(), new String(bytes)); byte[] bytes1 = oldBody.getBytes(); byte[] bytes2 = byteMerger(Arrays.copyOf(bytes,bytes.length-4), bytes1); Flux DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes2); DataBufferUtils.retain(buffer); return Mono.just(buffer); }); ServerHttpRequestDecorator mutatedRequest = newDecorator(exchange,bytes2.length,cachedFlux); ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build(); return ServerRequest.create(mutatedExchange, MESSAGE_READERS) .bodyToMono(byte[].class) .then(chain.filter(mutatedExchange)); }); } public static byte[] byteMerger(byte[] bt1, byte[] bt2){ byte[] bt3 = new byte[bt1.length+bt2.length]; System.arraycopy(bt1, 0, bt3, 0, bt1.length); System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length); return bt3; } //修改 x-www-form-urlencoded参数 private void changeParamByXwForm(Flux body.subscribe(dataBuffer -> { int len = dataBuffer.readableByteCount(); holder.length = len; byte[] bytes = new byte[len]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); String oldBody = new String(bytes, StandardCharsets.UTF_8); oldBody+="&test=修改数据"; DataBuffer data = outputMessage.bufferFactory().allocateBuffer(); data.write(oldBody.getBytes(StandardCharsets.UTF_8)); holder.length = data.readableByteCount(); holder.dataBuffer=data; }); } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } /** * 修改 x-www-form-urlencoded参数 * @param exchange * @param chain * @return */ private Mono ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); Mono BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); headers.remove(HttpHeaders.CONTENT_LENGTH); MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers); ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate(); requestBuilder.headers(k -> k.remove("Content-length")); return bodyInserter.insert(outputMessage, new BodyInserterContext()) .then(Mono.defer(() -> { Flux DataBufferHolder holder = new DataBufferHolder(); changeParamByXwForm(body,holder,outputMessage); ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer)); return chain.filter(exchange.mutate().request(decorator).build()); })); } /** * 修改修改body参数 */ private Mono ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders()); Mono BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class); HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getRequest().getHeaders()); headers.remove(HttpHeaders.CONTENT_LENGTH); MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers); ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate(); requestBuilder.headers(k -> k.remove("Content-length")); Mono mono = bodyInserter.insert(outputMessage, new BodyInserterContext()) .then(Mono.defer(() -> { //解决body内数据过长读取不完整的问题 Flux DataBufferHolder holder = new DataBufferHolder(); try{ body.subscribe(dataBuffer -> { int len = dataBuffer.readableByteCount(); holder.length = len; byte[] bytes = new byte[len]; dataBuffer.read(bytes); DataBufferUtils.release(dataBuffer); String oldBody = new String(bytes, StandardCharsets.UTF_8); JsonNode jsonNode = readNode(oldBody); checkTokenAndSaveUser((ObjectNode)jsonNode); DataBuffer data = outputMessage.bufferFactory().allocateBuffer(); data.write(jsonNode.toString().getBytes(StandardCharsets.UTF_8)); holder.length = data.readableByteCount(); holder.dataBuffer=data; }); }catch (Exception e){ if(e.getCause() instanceof ServiceException){ ServiceException e1 = (ServiceException) e.getCause(); return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(e1.getCode(), e1.getMessage()))); } return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(SYSTEM_ERROR.getCode(), SYSTEM_ERROR.getMessage()))); } ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer)); return chain.filter(exchange.mutate().request(decorator).build()); })); return mono; } private void checkTokenAndSaveUser(ObjectNode oldDataJSON) throws ServiceException{ JsonNode token = oldDataJSON.get("token"); if(token==null){ throw new ServiceException(TOKEN_NOT_EXISTENT_ERROR.getCode(), TOKEN_NOT_EXISTENT_ERROR.getMessage()); } Object userIdCacheKey = redisUtil.get(token.asText()); if(userIdCacheKey!=null){ Object cacheInfo = redisUtil.get(userIdCacheKey+""); UserCacheBO cacheDataObj = null; if(cacheInfo!=null){ cacheDataObj = (UserCacheBO) cacheInfo; }else{ cacheDataObj = userManager.flushUserCache(userIdCacheKey+"",token.asText()); } UserBO userBO = userConvert.cacheToBo(cacheDataObj); try { String s = JSON.toJSONString(userBO); JsonNode node = objectMapper.readTree(s); oldDataJSON.set("userBO",node); } catch (IOException e) { e.printStackTrace(); throw new IllegalStateException(e); } }else{ throw new ServiceException(TOKEN_NOT_EXISTENT_ERROR.getCode(), TOKEN_NOT_EXISTENT_ERROR.getMessage()); } } private Mono byte[] bytes = message.getBytes(StandardCharsets.UTF_8); DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes); exchange.getResponse().setStatusCode(HttpStatus.OK); return exchange.getResponse().writeWith(Flux.just(buffer)); } private JsonNode readNode(String in) { try { return objectMapper.readTree(in); } catch (Exception e) { throw new IllegalStateException(e); } } private class DataBufferHolder { DataBuffer dataBuffer; int length; } /** * 修改form参数 * @param contentType 请求类型 * @param bodyString 请求body信息 */ @SneakyThrows public static String addPara(String contentType, String bodyString) { StringBuffer stringBuffer = new StringBuffer(); String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9);//获取随机字符传信息 String boundary_end = StrUtil.format("--{}--\r\n", boundary); Map /** * * 根据自己需求进行对bodyString信息修改,例如下面,根据boundary对传入的bodyString进行了分割 * String[] split = bodyString.split(boundary); * 然后将修改完后的信息封装到formMap中,需要注意的是,file文件需要以new FileResource(file, fileName)的形式当作value放到formMap中 */ String part = "^\r\nContent-Disposition: form-data; name=\"([^/?]+)\"\r\n\r\n([^/?]+)\r\n--?$"; Pattern r = Pattern.compile(part); String[] split = bodyString.split(boundary); for(int x=1;x Matcher m = r.matcher(split[x]); if(m.find()){ String name = m.group(1); String value = m.group(2); System.out.println("name:"+name+" value:"+value); // formMap.put(name,value); } } formMap.put("ft",11111); formMap.put("tcu",22222); Integer count =0; for (Map.Entry stringBuffer.append(appendPart(boundary, entry.getKey(), entry.getValue(),count)); count++; } stringBuffer.append(boundary_end);//拼接结束信息 log.info(stringBuffer.toString()); return stringBuffer.toString(); } public ServerHttpRequestDecorator newDecorator(ServerWebExchange exchange,long dataLength,Flux return new ServerHttpRequestDecorator( exchange.getRequest()) { @Override public HttpHeaders getHeaders() { //数据长度变了以后 需要修改header里的数据,不然接收数据时会异常 //我看别人说删除会自动补充数据长度,但我这个版本不太行 // long contentLength = headers.getContentLength(); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); // if (contentLength > 0) { httpHeaders.setContentLength(dataLength); // } else { // httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); // } return httpHeaders; } @Override public Flux return body; } }; } /** * 添加Multipart表单的数据项 * * @param boundary 随机串信息 * @param formFieldName 表单名 * @param value 值,可以是普通值、资源(如文件等) */ private static String appendPart(String boundary, String formFieldName, Object value,Integer count) throws IORuntimeException { StringBuffer stringBuffer = new StringBuffer(); // 多资源 if (value instanceof MultiResource) { for (Resource subResource : (MultiResource) value) { appendPart(boundary, formFieldName, subResource,count); } return stringBuffer.toString(); } if(count!=0){ stringBuffer.append("--").append(boundary).append(StrUtil.CRLF); }else{ stringBuffer.append(StrUtil.CRLF); // stringBuffer.append(boundary).append(StrUtil.CRLF); } if (value instanceof Resource) { // 文件资源(二进制资源) final Resource resource = (Resource) value; final String fileName = resource.getName(); stringBuffer.append(StrUtil.format(CONTENT_DISPOSITION_FILE_TEMPLATE, formFieldName, ObjectUtil.defaultIfNull(fileName, formFieldName))); // 根据name的扩展名指定互联网媒体类型,默认二进制流数据 stringBuffer.append(StrUtil.format(CONTENT_TYPE_FILE_TEMPLATE, HttpUtil.getMimeType(fileName, "application/octet-stream"))); } else { // 普通数据 stringBuffer.append(StrUtil.format(CONTENT_DISPOSITION_TEMPLATE, formFieldName)).append(value); } stringBuffer.append(StrUtil.CRLF); return stringBuffer.toString(); } } MyCachedBodyOutputMessage.java import java.util.function.Supplier; import org.reactivestreams.Publisher; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DataBufferFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.ReactiveHttpOutputMessage; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; public class MyCachedBodyOutputMessage implements ReactiveHttpOutputMessage { private final DataBufferFactory bufferFactory; DataBuffer dataBuffer; private final HttpHeaders httpHeaders; private Flux public MyCachedBodyOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) { this.bufferFactory = exchange.getResponse().bufferFactory(); this.httpHeaders = httpHeaders; } @Override public void beforeCommit(Supplier extends Mono } @Override public boolean isCommitted() { return false; } @Override public HttpHeaders getHeaders() { return this.httpHeaders; } @Override public DataBufferFactory bufferFactory() { return this.bufferFactory; } public Flux return this.body; } @Override public Mono this.body = Flux.from(body); return Mono.empty(); } @Override public Mono return this.writeWith(Flux.from(body).flatMap((p) -> { return p; })); } @Override public Mono return this.writeWith(Flux.empty()); } } 修改返回值代码 import com.google.common.base.Joiner; import com.google.common.base.Throwables; import org.apache.commons.lang3.StringUtils; import org.reactivestreams.Publisher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.zip.GZIPOutputStream; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR; @Component public class ResponseFilter implements GlobalFilter, Ordered { private static final Logger log = LoggerFactory.getLogger(ResponseFilter.class); private static Joiner joiner = Joiner.on(""); // @Autowired // private IgnoreWhiteProperties ignoreWhite; /** * 约定的压缩格式 */ private final static String GZIP = "gzip"; @Override public Mono String acceptEncoding = exchange.getRequest().getHeaders().getFirst("Accept-Encoding"); ServerHttpResponse originalResponse = exchange.getResponse(); DataBufferFactory bufferFactory = originalResponse.bufferFactory(); ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { @Override public Mono if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) { // 获取ContentType,判断是否返回JSON格式数据 String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR); if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) { Flux extends DataBuffer> fluxBody = Flux.from(body); //(返回数据内如果字符串过大,默认会切割)解决返回体分段传输 return super.writeWith(fluxBody.buffer().map(dataBuffers -> { List dataBuffers.forEach(dataBuffer -> { try { byte[] content = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(content); DataBufferUtils.release(dataBuffer); list.add(new String(content, StandardCharsets.UTF_8)); } catch (Exception e) { log.info("加载Response字节流异常,失败原因:{}", Throwables.getStackTraceAsString(e)); } }); String responseData = joiner.join(list); System.out.println("responseData:"+responseData); String responseDataEncode = null; // String responseDataEncode = AESUtil.aesEncodeByKey(responseData, "MP5v0^zee5Qlgq5V"); if(responseDataEncode==null){ return bufferFactory.wrap(responseData.getBytes(StandardCharsets.UTF_8)); } responseDataEncode = responseDataEncode.replaceAll("\r\n", "").replaceAll("\n",""); byte[] uppedContent = new String(responseDataEncode.getBytes(), StandardCharsets.UTF_8).getBytes(); originalResponse.getHeaders().setContentLength(uppedContent.length); if(!StringUtils.isAnyBlank(acceptEncoding)){ assert acceptEncoding != null; //是否支持压缩 if(acceptEncoding.contains(GZIP)){ //支持压缩 ByteArrayOutputStream bout = new ByteArrayOutputStream(); //压缩输出流中的数据 GZIPOutputStream gout; try { gout = new GZIPOutputStream(bout); gout.write(uppedContent); gout.close(); uppedContent = bout.toByteArray(); originalResponse.getHeaders().setContentLength(uppedContent.length); originalResponse.getHeaders().set("content-encoding", GZIP); } catch (IOException e) { e.printStackTrace(); } }else{ originalResponse.getHeaders().setContentLength(uppedContent.length); } } return bufferFactory.wrap(uppedContent); })); } } return super.writeWith(body); } }; return chain.filter(exchange.mutate().response(decoratedResponse).build()); } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } } 参考文章:https://blog.csdn.net/Hardworking666/article/details/123833192 精彩文章
发表评论