前言:

记一次 Gateway 读取响应内容时导致中文乱码。
问题还是比较严重的,因为这个问题导致系统全局中文出现偶发性乱码,经过 debug 追踪,最终确认了是在 gateway 获取响应内容重写时出现了问题。

场景复现:

先看代码,方法的功能是读取响应结果,并记录响应结果。

 /**
     * 记录响应日志
     *
     * @param exchange
     * @return
     */
    private ServerHttpResponseDecorator logResponse(ServerWebExchange exchange, LogReq logReq) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        // 定义 response
        ServerHttpResponseDecorator response = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
				// 略...
				
               // 注意:此处切分多次读取将导致问题的出现
                 dataBuffers.forEach(dataBuffer -> {
                     try {
                         byte[] content = new byte[dataBuffer.readableByteCount()];
                         dataBuffer.read(content);
                         responseContentList.add(new String(content, StandardCharsets.UTF_8));
                     } catch (Exception e) {
                         log.error("加载 Response 字节流异常,失败原因:{}", Throwables.getStackTraceAsString(e));
                     } finally {
                         DataBufferUtils.release(dataBuffer);
                     }
                 });
                 
				// 略...                           
            }

            @Override
            public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }
        };

        return response;
    }

在 dataBuffers 中如果响应过大可能会将字符串分批读取,那么这就存在一个问题,当需要读取的字符串的某个字被切分了,将导致那个字乱码。如:伞兵一号卢本伟,由于是按字节分批读取,假如分成两批,伞兵一号卢本伟,如果字被拆开了,那么将导致乱码了。

{
	"status": ,
	"data": {
		"title": "伞兵一��卢本伟"
	},
	"message": ""
}

解决方案:

做法很明显就是不要分批,通过 DefaultDataBufferFactory 将 dataBuffers 合并为一个再读取,实现如下:

DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer dataBuffer = dataBufferFactory.join(dataBuffers);
try {
    byte[] content = new byte[dataBuffer.readableByteCount()];
    dataBuffer.read(content);
    responseContentList.add(new String(content, StandardCharsets.UTF_8));
} catch (Exception e) {
    log.error("加载 Response 字节流异常,失败原因:{}", Throwables.getStackTraceAsString(e));
} finally {
    DataBufferUtils.release(dataBuffer);
}

合并完成后再读取,中文乱码解决!!!

{
	"status": ,
	"data": {
		"title": "伞兵一号卢本伟"
	},
	"message": ""
}

如果此博客有帮助到您,请不要忘记点赞喔~

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐