新项目需要在getway统一做入参、出参加解密,记录日志。记录一下form,x-www-form-urlencoded , json 这几种修改数据的方式。
gateway做拦截器是实现GlobalFilter接口,修改json方式网上有很多文章,后来又想研究研究能不能实现修改form-data参数,以及文件请求,后者文章不多大部分是怎么读数据的教学。现在发一下我的实现方式。
使用的gateway版本是2.2.1.RELEASE cloud版本Greenwich.SR2
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Mono<Void> mono = chain.filter(exchange);
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<String, String> queryParams = exchange.getRequest().getQueryParams().toSingleValueMap();
log.info("queryParams:{}", queryParams);
}
}
return mono;
}
修改json数据
/**
* 修改修改body参数
*/
private Mono<Void> transferBody(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);
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<DataBuffer> body = outputMessage.getBody();
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<Void> fileRequest(MediaType contentType,ServerWebExchange exchange, GatewayFilterChain chain){
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> cachedFlux = Flux.defer(() -> {
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<String, Object> formMap = Maps.newHashMap();
/**
*
* 根据自己需求进行对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<split.length-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<String, Object> entry : formMap.entrySet()) {
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<Void> xwFromBody(ServerWebExchange exchange, GatewayFilterChain chain){
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);
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<DataBuffer> body = outputMessage.getBody();
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<DataBuffer> body,DataBufferHolder holder,MyCachedBodyOutputMessage outputMessage){
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<HttpMessageReader<?>> MESSAGE_READERS = HandlerStrategies.withDefaults().messageReaders();
@Autowired
private RedisUtil redisUtil;
@Autowired
private UserConvert userConvert;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private UserManager userManager;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Mono<Void> mono = chain.filter(exchange);
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<String, String> queryParams = exchange.getRequest().getQueryParams().toSingleValueMap();
log.info("queryParams:{}", queryParams);
}
}
return mono;
}
//修改form参数
private Mono<Void> fileRequest(MediaType contentType,ServerWebExchange exchange, GatewayFilterChain chain){
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> cachedFlux = Flux.defer(() -> {
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<DataBuffer> body,DataBufferHolder holder,MyCachedBodyOutputMessage outputMessage){
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<Void> xwFromBody(ServerWebExchange exchange, GatewayFilterChain chain){
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);
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<DataBuffer> body = outputMessage.getBody();
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<Void> transferBody(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);
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<DataBuffer> body = outputMessage.getBody();
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<Void> handleFailedRequest(ServerWebExchange exchange, String message) {
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<String, Object> formMap = Maps.newHashMap();
/**
*
* 根据自己需求进行对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<split.length-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<String, Object> entry : formMap.entrySet()) {
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<DataBuffer> body){
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<DataBuffer> getBody() {
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<DataBuffer> body = Flux.error(new IllegalStateException("The body is not set. Did handling complete with success?"));
public MyCachedBodyOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) {
this.bufferFactory = exchange.getResponse().bufferFactory();
this.httpHeaders = httpHeaders;
}
@Override
public void beforeCommit(Supplier<? extends Mono<Void>> action) {
}
@Override
public boolean isCommitted() {
return false;
}
@Override
public HttpHeaders getHeaders() {
return this.httpHeaders;
}
@Override
public DataBufferFactory bufferFactory() {
return this.bufferFactory;
}
public Flux<DataBuffer> getBody() {
return this.body;
}
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
this.body = Flux.from(body);
return Mono.empty();
}
@Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return this.writeWith(Flux.from(body).flatMap((p) -> {
return p;
}));
}
@Override
public Mono<Void> setComplete() {
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<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String acceptEncoding = exchange.getRequest().getHeaders().getFirst("Accept-Encoding");
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
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<String> list = new ArrayList<>();
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