Spring Cloud Gateway修改响应体后内容被截断问题求助
解决Spring Cloud Gateway修改响应体后缓冲区截断的问题
嘿,这个问题我之前也碰到过!你已经成功修改了响应体,但忽略了一个关键步骤:更新响应头里的Content-Length字段,同时还要处理分块编码的情况。
原响应的Content-Length还是旧内容的长度,所以客户端(比如浏览器)会按照这个长度去读取新的响应体,自然就把超出部分截断了。下面是修改后的完整代码,我会给你标注关键修改点:
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.HttpHeaders; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; public class ModifyBodyGatewayFilterImpl implements GatewayFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpResponse originalResponse = exchange.getResponse(); DataBufferFactory bufferFactory = originalResponse.bufferFactory(); ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { // 1. 收集原响应的所有数据(若无需原内容,可直接跳过并释放原缓冲区) return Flux.from(body) .reduce((buffer1, buffer2) -> { // 合并原响应的所有缓冲区 DataBuffer mergedBuffer = bufferFactory.allocateBuffer( buffer1.readableByteCount() + buffer2.readableByteCount()); mergedBuffer.write(buffer1); mergedBuffer.write(buffer2); // 释放原缓冲区,避免内存泄漏 DataBufferUtils.release(buffer1); DataBufferUtils.release(buffer2); return mergedBuffer; }) .map(mergedBuffer -> { // 2. 生成新的响应内容 String newResponseContent = "0123456789abcdefg"; byte[] newContentBytes = newResponseContent.getBytes(StandardCharsets.UTF_8); // 3. 释放原合并的缓冲区 DataBufferUtils.release(mergedBuffer); // 4. 分配对应大小的新缓冲区并写入内容 DataBuffer newBuffer = bufferFactory.allocateBuffer(newContentBytes.length); newBuffer.write(newContentBytes); // 5. 关键:更新响应头 HttpHeaders headers = getDelegate().getHeaders(); // 设置新的Content-Length为新内容的字节长度 headers.setContentLength(newContentBytes.length); // 如果原响应使用了分块编码,移除这个头(因为现在是固定长度) headers.remove(HttpHeaders.TRANSFER_ENCODING); return newBuffer; }) // 6. 将新缓冲区转为Flux,交给父类处理 .flatMap(newBuffer -> super.writeWith(Flux.just(newBuffer))); } }; // 替换响应为装饰后的响应 ServerWebExchange updatedExchange = exchange.mutate().response(decoratedResponse).build(); return chain.filter(updatedExchange); } }
关键修改点说明:
- 更新
Content-Length:这是解决截断问题的核心,让客户端明确知道新响应体的实际长度。 - 释放原缓冲区:一定要记得释放原响应的缓冲区,避免内存泄漏。
- 处理分块编码:如果原响应是分块传输(
Transfer-Encoding: chunked),需要移除这个头,否则客户端可能会以分块方式解析固定长度的内容,导致异常。
如果不需要原响应的内容,还可以简化代码,直接跳过收集原数据的步骤,效率更高:
@Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { // 直接释放所有原缓冲区 DataBufferUtils.release(body); String newResponseContent = "0123456789abcdefg"; byte[] newContentBytes = newResponseContent.getBytes(StandardCharsets.UTF_8); // 更新响应头 HttpHeaders headers = getDelegate().getHeaders(); headers.setContentLength(newContentBytes.length); headers.remove(HttpHeaders.TRANSFER_ENCODING); DataBuffer newBuffer = bufferFactory.allocateBuffer(newContentBytes.length); newBuffer.write(newContentBytes); return super.writeWith(Flux.just(newBuffer)); }
这样修改后,新的响应体就不会被截断了,客户端会完整接收你设置的内容。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

