首页 > 其他分享 >记一次springcloud gateway记录日志响应结果乱码问题

记一次springcloud gateway记录日志响应结果乱码问题

时间:2025-01-14 10:22:05浏览次数:1  
标签:return Encoding springcloud Accept 乱码 响应 编码方式 gateway

前言

最近团队的网关日志发现有不少响应结果记录,出现形如下的乱码

       �V*.I,IU�JK�)N�Q�M-.NL�^�m�?��(�钍/�,}�����]O7L|���ŲƧ�MϦnP�Q*K�)*�+���QJ-*�/r�O���{�@8�    ��

一开始感觉是不是中文乱码,但是后面发现有些日志不是中文,也是乱码,而有些记录的日志又能正常显示。于是搜索了一圈,在https://blog.csdn.net/u013506626/article/details/134487673
在这篇文章找到的思路以及解决答案。

如何解决

根据上面博文介绍是因为请求的headers中加了有"Accept-Encoding"属性,值为"gzip, deflate, br",导致响应结果乱码。解决思路就是将Accept-Encoding置为空“”就可以解决,按他的思路,我就写了一个过滤器

@RequiredArgsConstructor
public class RemoveGzipHeaderGlobalFilter implements Ordered, GlobalFilter {

    private final GwCommonProperty gwCommonProperty;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (isSkipRemoveGzipHeaderEnabled(exchange)) {
            return chain.filter(exchange);
        } else {
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .header(HttpHeaders.ACCEPT_ENCODING, "").build();
            return chain.filter(exchange.mutate().request(request).build());

        }
    }

    private boolean isSkipRemoveGzipHeaderEnabled(ServerWebExchange exchange){
        if(!gwCommonProperty.isRemoveGzipHeaderEnabled()){
            return true;
        }
        String gzipHeader = exchange.getRequest().getHeaders().getFirst(HttpHeaders.ACCEPT_ENCODING);

        if(!StringUtils.hasText(gzipHeader)){
            return true;
        }
        return !gzipHeader.contains("gzip");

    }

@Override
public int getOrder() {
    return Ordered.HIGHEST_PRECEDENCE;
    }
}

后面果然不再出现乱码。既然是Accept-Encoding引起的乱码问题,我们就来聊下Accept-Encoding

Accept-Encoding

Accept-Encoding 是 HTTP 协议中的一个头部字段,其主要作用在于告知服务器,客户端能够理解的内容编码方式。这个字段对于网络传输效率的优化非常重要,因为它允许服务器根据客户端的能力来压缩响应数据,从而减少传输的数据量,加快网页加载速度。

1、常见编码方式:

gzip: 使用 Lempel-Ziv 编码(LZ77)和 Huffman 编码进行压缩的算法。
deflate: 使用 zlib 库和 deflate 压缩算法进行压缩。
br(Brotli): Google 开发的一种新的数据压缩算法,旨在提供比 gzip 和 deflate 更高的压缩率。

2、字段格式:

Accept-Encoding 字段的值是一个由逗号分隔的列表,其中包含了客户端支持的内容编码方式。例如:Accept-Encoding: gzip, deflate, br

3、工作流程:

客户端在发送 HTTP 请求时,会在请求头部中包含 Accept-Encoding 字段,列出它支持的内容编码方式。

服务器在收到请求后,会检查 Accept-Encoding 字段,并根据客户端支持的内容编码方式来选择合适的压缩算法来压缩响应数据。

如果服务器选择了一种内容编码方式,它会在响应头部的 Content-Encoding 字段中指定所使用的编码方式。

网关日志记录响应结果乱码原因

介绍完Accept-Encoding,我们继续探讨一下为啥Accept-Encoding会引起网关日志响应结果乱码,因为设置了Accept-Encoding: gzip,deflate,所以服务器就会根据客户端支持的内容编码方式来选择合适的压缩算法来压缩响应,而网关层数据没对数据进行解压缩,因此就乱码

因此解决乱码的思路理论上会有2种,一种是上述博文介绍的,去掉Accept-Encoding: gzip,deflate这个头信息。去掉这个头信息就是告诉服务器,客户端不支持压缩,要求不压缩直接返回数据

另外一种思路是如果服务器选择了一种内容编码方式,它会在响应头部的 Content-Encoding 字段中指定所使用的编码方式。因此我们就可以根据Content-Encoding来判断是否要对数据进行解压缩

网关日志记录过滤器核心改造的示例如下

 /**
     * 记录响应日志
     * 通过 DataBufferFactory 解决响应体分段传输问题。
     */
  private ServerHttpResponseDecorator recordResponseLog(ServerWebExchange exchange, AccessLog accessLog) {
        ServerHttpResponse response = exchange.getResponse();
        DataBufferFactory bufferFactory = response.bufferFactory();
        return new ServerHttpResponseDecorator(response) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    LogUtils.setReponse(accessLog,exchange);
                    Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                        // 合并多个流集合,解决返回体分段传输
                    DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                    DataBuffer join = dataBufferFactory.join(dataBuffers);
                    byte[] content = new byte[join.readableByteCount()];
                    join.read(content);


                    content = isGzip(response) ? gzipMessageBodyResolver.decode(content) : content;

                    // 释放掉内存
                    DataBufferUtils.release(join);
                    String responseResult = new String(content, StandardCharsets.UTF_8);

                    accessLog.setResponseData(responseResult);

                        return bufferFactory.wrap(content);
                    }));
                    }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };
    }



    public boolean isGzip(ServerHttpResponse serverHttpResponse) {
        HttpHeaders headers = serverHttpResponse.getHeaders();
        if (headers.containsKey(HttpHeaders.CONTENT_ENCODING)) {
            List<String> encodingList = headers.get(HttpHeaders.CONTENT_ENCODING);
            return CollectionUtil.isNotEmpty(encodingList) && encodingList.contains(GZIP);
        }
        return false;
    }




注: 特别提醒,因为要获取服务端header响应Content-Encoding,用的是ServerHttpResponse,而不是ServerHttpRequest

总结

综上解决因Accept-Encoding引起的乱码方式有2种,一种是直接移除Accept-Encoding,告诉服务端不要对响应数据进行压缩,直接返回未压缩数据。另外一种如果不移除Accept-Encoding,就得根据Content-Encoding来对服务端响应的数据进行解压缩

标签:return,Encoding,springcloud,Accept,乱码,响应,编码方式,gateway
From: https://www.cnblogs.com/linyb-geek/p/18362506

相关文章

  • 解释下你对GBK和UTF-8的理解?并说说页面上产生乱码的可能原因
    对GBK和UTF-8的理解:GBK和UTF-8是两种常见的字符编码方式,它们主要用于将字符转换为二进制数据,以便在计算机中进行存储和传输。GBK编码:GBK编码主要支持中文和日韩字符,适合在国内应用中使用。它采用双字节编码,即每个字符通常占用2个字节的空间。GBK编码是GB2312的扩展,包含了......
  • MySQL数据库出现乱码怎么解决
    为什么我的数据库总会出现中文乱码的情况。一堆中文乱码不知道怎么回事?当向数据库中写入创建表,并插入中文时,会出现这种问题。此报错会涉及数据库字符集的问题。.1解决乱码的几个方面对于中文乱码的情况,从三个方面数据终端:就是我们连接数据库的工具设置为utf8操作系统层面:l......
  • SpringCloud微服务(十二)
    前言:此篇文章系本人学习过程中记录下来的笔记,里面难免会有不少欠缺的地方,诚心期待大家多多给予指教。 往期目录回顾: SpringCloud微服务(一)SpringCloud微服务(二)SpringCloud微服务(三)SpringCloud微服务(四)SpringCloud微服务(五)SpringCloud微服务(六)SpringCloud微服务(七)SpringClo......
  • matplotlib显示中文乱码问题
    一背景最近使用matplotlib,画图时候,出现中文乱码,在此记录解决方案。二bug现象三解决方案在代码中添加如下importmatplotlibasmplfont_path='/home/xx/Downloads/chinese.simhei.ttf'mpl.font_manager.fontManager.addfont(font_path)mpl.rc('font',famil......
  • SpringCloud 解决 Docker 镜像 虚拟机网卡导致的IP 不准确的问题
    SpringCloud应用可能会使用InetAddress.getLocalHost().getHostAddress()或类似方法来获取当前机器的IP地址。但在Docker容器环境中,这种方法可能会返回容器内部的IP地址,而不是宿主机的IP地址。分布式应用部署到服务上,由于服务器可能存在多张网卡,造成IP地址不准。出......
  • SpringCloud
    认识微服务单体架构在认识微服务之前,我先来说说单体架构,我们之前所学的SpringBoot做的最多项目就是单体架构项目。而单体架构是将业务的所有功能集中在一个项目中开发,打成一个包部署。所以单体架构的优缺点就十分的明显,如下图表示。微服务架构而微服务就是把单体架构中某些功......
  • Qt中文乱码的一种解决方法(ISO-8859-1和GBK编码互转)
    问题描述:在老项目数据库中,中文显示乱码,编码格式未知,一度怀疑进行了加密。问题定位:最终,经过大佬的尝试,发现是编码格式的问题。老项目中是将GBK编码的中文字符按照ISO-8859-1编码存入,导致乱码。解决方法(Qt):voidtest(){//读取数据库QSqlDatabasedb;QSqlQuery......
  • Eureka加密 及Gateway搭建 - 基于SpringBoot不同版本配置方式
    前言:在最近开发过程中偶遇根据SpringBoot不同版本导致配置方式不一致等问题通用:Eureka服务配置Server端:一、引入依赖spring-boot-starter-security<dependencies> <!--Eureka声明依赖--><dependency><groupId>org.springframework.cloud</groupId>......
  • SpringCloud
    SpringCloudSpringCloudAlibaba5大组件有哪些?​ 服务注册和配置中心Nacos,负载均衡Ribbon,服务调用Feign,服务保护(包括限流降级熔断)sentinel,服务的网关Gateway注:每个微服务都要注册和配置一些东西需要Nacos,一个微服务部署集群即多个实例还要用到负载均衡Ribbon,服务间互相......
  • SpringCloud 应用 Nacos 配置中心注解
    作者:柳遵飞前言在SpringCloud应用中可以非常低成本地集成Nacos实现配置动态刷新,在应用程序代码中通过Spring官方的注解@Value和@ConfigurationProperties,引用Springenviroment上下文中的属性值,关于这部分的介绍可以参照《SpringCloud+Nacos+KMS动态配置最佳实践......