一、問題定位
在做微服務(wù)項目的時候,使用Spring Cloud Gateway會時不時亂碼
亂碼字符是這樣的:“???”
在排除了一系列數(shù)據(jù)庫編碼設(shè)置、resoonse流字符設(shè)置等可能導(dǎo)致亂碼的情況后,直接調(diào)用服務(wù)不亂碼,通過網(wǎng)關(guān)就會亂碼,確定了是響應(yīng)數(shù)據(jù)在gateway中發(fā)生了亂碼。
二、錯誤使用
ServerHttpResponseDecorator decorator = new ServerHttpResponseDecorator(response) { @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { if (body instanceof Flux) { Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>)body; return super.writeWith(fluxBody.buffer().map(dataBuffers -> { List<String> list = Lists.newArrayList(); // gateway 針對返回參數(shù)過長的情況下會分段返回,使用如下方式接受返回參數(shù)則可避免 dataBuffers.forEach(dataBuffer -> { // probably should reuse buffers byte[] content = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(content); // 釋放掉內(nèi)存 DataBufferUtils.release(dataBuffer); list.add(new String(content, StandardCharsets.UTF_8)); }); // 將多次返回的參數(shù)拼接起來 String responseData = joiner.join(list); // 重置返回參數(shù) String result = response(responseData); byte[] uppedContent = new String(result.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8).getBytes(); // 修改后的返回參數(shù)應(yīng)該重置長度,否則如果修改后的參數(shù)長度超出原始參數(shù)長度時會導(dǎo)致客戶端接收到的參數(shù)丟失一部分 response.getHeaders().setContentLength(uppedContent.length); return bufferFactory.wrap(uppedContent); })); } return super.writeWith(body); } };
網(wǎng)關(guān)是請求的出入口如果響應(yīng)過大的話,F(xiàn)lux會進行截斷,可能會導(dǎo)致亂碼。。按照我的理解是,響應(yīng)數(shù)據(jù)在到達Flux時,已經(jīng)是一串byte字節(jié)數(shù)據(jù),如果這個byte數(shù)據(jù)被截斷,大概率其截斷點不會剛好是某一個字符的最后一個字節(jié)數(shù)據(jù)。比如一個字符串中,每個字符占10個字節(jié),只有當截取的字節(jié)長度為10、20或30時,也就是截取下來字符剛好都是完整的字符才不會出現(xiàn)亂碼。但是當截取的字節(jié)長度為12、23或34時,剛好只截取到了最后一個字符的一部分字節(jié)數(shù)據(jù),而另一部分丟失了時就會出現(xiàn)亂碼。
三、正確使用
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
Flux<? extends DataBuffer> flux = (Flux<? extends DataBuffer>) body;
return super.writeWith(flux.buffer().map(dataBuffers -> {
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
//dataBuffer合并成一個,解決獲取結(jié)果不全問題
DataBuffer join = dataBufferFactory.join(dataBuffers);
byte[] content = new byte[join.readableByteCount()];
join.read(content);
//釋放掉內(nèi)存
DataBufferUtils.release(join);
//formatResponse對獲取的結(jié)果進行修改,可根據(jù)自身業(yè)務(wù)需求做修改
String response = formatResponse(content, exchange);
//修改響應(yīng)結(jié)果長度
byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
originalResponse.getHeaders().setContentLength(responseBytes.length);
return bufferFactory.wrap(responseBytes);
}));
}
return super.writeWith(body);
}
};
結(jié)論:DataBufferFactory的join方法能解決獲取結(jié)果不全問題,使用它拼接的流是完整沒有截斷的







暫無評論,快來評論吧!