SpringCloud-Gateway修改Response响应体,并解决大数据量返回不全等问题

官网相关案例:

Spring Cloud Gatewayhttps://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-modifyresponsebody-gatewayfilter-factory

复制代码
ModifyRequestBodyGatewayFilterFactory类:

https://github.com/spring-cloud/spring-cloud-gateway/blob/3.1.x/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.javahttps://github.com/spring-cloud/spring-cloud-gateway/blob/3.1.x/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/filter/factory/rewrite/ModifyResponseBodyGatewayFilterFactory.java

相关代码:

java 复制代码
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
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.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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.util.List;
 
/**
 * @Author: meng
 * @Description: 自定义返回体 - 借鉴原生类ModifyRequestBodyGatewayFilterFactory实现
 * https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the
 * -modifyresponsebody-gatewayfilter-factory
 * @Date: 2023/4/18 13:37
 * @Version: 1.0
 */
@Slf4j
@Component
public class ResponseGatewayFilterFactory extends AbstractGatewayFilterFactory<ResponseGatewayFilterFactory.Config> {
 
	public ResponseGatewayFilterFactory() {
		super(Config.class);
	}
 
	@Data
	@AllArgsConstructor
	@NoArgsConstructor
	public static class Config {
 
		// 不需要自定义的接口
		List<String> pathExclude;
 
	}
 
	@Override
	public GatewayFilter apply(Config config) {
		RewriteResponseGatewayFilter rewriteResponseGatewayFilter = new RewriteResponseGatewayFilter(config);
		return rewriteResponseGatewayFilter;
	}
 
	public class RewriteResponseGatewayFilter implements GatewayFilter, Ordered {
 
		private Config config;
 
		public RewriteResponseGatewayFilter(Config config) {
			this.config = config;
		}
 
		@Override
		public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
			// 不需要自定义的接口,直接返回
			log.info("pathExclude:{}", config.pathExclude);
			if (CollUtil.isNotEmpty(config.pathExclude)) {
				long count = config.pathExclude.stream()
					.filter(uri -> StrUtil.contains(exchange.getRequest().getPath().toString(), uri))
					.count();
				if (count > 0) {
					return chain.filter(exchange);
				}
			}
			String appId = exchange.getRequest().getHeaders().getFirst("X-APPID");
			if (StrUtil.isBlank(appId)) {
				return buildResponse(exchange, HttpStatus.UNAUTHORIZED.value(), "appId不能为空");
			}
			ServerHttpResponse originalResponse = exchange.getResponse();
			DataBufferFactory bufferFactory = originalResponse.bufferFactory();
			try {
				ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
					@Override
					public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
						if (body instanceof Flux) {
							Flux<? extends DataBuffer> fluxBody = Flux.from(body);
							return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
								byte[] newContent = new byte[0];
								try {
									DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
									DataBuffer join = dataBufferFactory.join(dataBuffers);
									byte[] content = new byte[join.readableByteCount()];
									join.read(content);
									DataBufferUtils.release(join);
									// 获取响应数据
									String responseStr = new String(content, "UTF-8");
									// 修改响应数据
									JSONObject jsonObject = new JSONObject();
									jsonObject.put("code", HttpStatus.UNAUTHORIZED.value());
									jsonObject.put("message", "请求成功");
									jsonObject.put("data", responseStr);
									String message = jsonObject.toJSONString();
									newContent = message.getBytes("UTF-8");
									originalResponse.getHeaders().setContentLength(newContent.length);
								}
								catch (Exception e) {
									log.error("appId:{}, responseStr exchange error:{}", appId, e);
									throw new RuntimeException(e);
								}
								return bufferFactory.wrap(newContent);
							}));
						}
						return super.writeWith(body);
					}
 
					@Override
					public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
						return writeWith(Flux.from(body).flatMapSequential(p -> p));
					}
				};
				return chain.filter(exchange.mutate().response(decoratedResponse).build());
			}
			catch (Exception e) {
				log.error("RewriteResponse error:{}", e);
				return Mono.error(new Exception("RewriteResponse fail", e));
			}
		}
 
		@Override
		public int getOrder() {
			return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 2;
		}
 
	}
 
	@SneakyThrows
	public static Mono<Void> buildResponse(ServerWebExchange exchange, int code, String message) {
		ServerHttpResponse response = exchange.getResponse();
		response.setStatusCode(HttpStatus.OK);
		response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("code", code);
		jsonObject.put("message", message);
		jsonObject.put("data", "");
		byte[] bytes = jsonObject.toJSONString().getBytes("UTF-8");
		DataBuffer bodyDataBuffer = response.bufferFactory().wrap(bytes);
		return response.writeWith(Mono.just(bodyDataBuffer));
	}
 
}
相关推荐
gadiaola8 分钟前
【JavaSE面试篇】Java集合部分高频八股汇总
java·面试
艾迪的技术之路31 分钟前
redisson使用lock导致死锁问题
java·后端·面试
今天背单词了吗9801 小时前
算法学习笔记:8.Bellman-Ford 算法——从原理到实战,涵盖 LeetCode 与考研 408 例题
java·开发语言·后端·算法·最短路径问题
天天摸鱼的java工程师1 小时前
使用 Spring Boot 整合高德地图实现路线规划功能
java·后端
东阳马生架构1 小时前
订单初版—2.生单链路中的技术问题说明文档
java
咖啡啡不加糖1 小时前
暴力破解漏洞与命令执行漏洞
java·后端·web安全
风象南1 小时前
SpringBoot敏感配置项加密与解密实战
java·spring boot·后端
DKPT2 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
Percep_gan2 小时前
idea的使用小技巧,个人向
java·ide·intellij-idea