Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jeecg-boot clound 3.5.0 版本 网关全局过滤器 response body 读取乱码问题 #4680

Closed
fzw2408 opened this issue Mar 13, 2023 · 1 comment

Comments

@fzw2408
Copy link

fzw2408 commented Mar 13, 2023

版本号:

jeecg-boot clound 3.5.0

前端版本:vue3版?还是 vue2版?
问题描述:

jeecg-boot clound 3.5.0 版本 网关全局过滤器 response body 读取乱码问题 【list.add(new String(content, "utf-8")); 尝试过gbk Unicode 等均乱码】,尝试试过自己写的服务读取body数据正常。而且仅开了JeecgSystemCloudApplicants 。测试的接口是获取验证码的接口。
http://localhost:9999/sys/randomImage/1629428467008?_t=1678679615058;
http://localhost:7001/sys/randomImage/1629428467008?_t=1678679615058;
网关没有加过滤器,访问该接口正常。
加了过滤器,只要尝试修改body内容,接口还回就异常。

截图&代码:

/*

  •  Copyright (c) 2018-2028, DreamLu All rights reserved.
    
  • Redistribution and use in source and binary forms, with or without
  • modification, are permitted provided that the following conditions are met:
  • Redistributions of source code must retain the above copyright notice,
  • this list of conditions and the following disclaimer.
  • Redistributions in binary form must reproduce the above copyright
  • notice, this list of conditions and the following disclaimer in the
  • documentation and/or other materials provided with the distribution.
  • Neither the name of the dreamlu.net developer nor the names of its
  • contributors may be used to endorse or promote products derived from
  • this software without specific prior written permission.
  • Author: DreamLu 卢春梦 (596392912@qq.com)
    */
    package org.jeecg.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
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.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.util.List;

/**

  • webflux 相应日志,方便开发调试,注意排序要优先。

  • @author dream.lu
    */
    @slf4j
    @configuration
    @requiredargsconstructor
    public class GlobalResponseLogFilter implements GlobalFilter, Ordered {
    private final WebEndpointProperties endpointProperties;
    private final ObjectMapper objectMapper;
    private static Joiner joiner = Joiner.on("");

    @OverRide
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

     ServerHttpResponse originalResponse = exchange.getResponse();
     originalResponse.getHeaders().add("Content-Type", "text/plain;charset=UTF-8");
     DataBufferFactory bufferFactory = originalResponse.bufferFactory();
     ServerHttpResponseDecorator response = new ServerHttpResponseDecorator(originalResponse) {
     	@Override
     	public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
     		if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
     			// 获取ContentType,判断是否返回JSON格式数据
     			String originalResponseContentType = exchange.getAttribute("original_response_content_type");
     			if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {
     				Flux<? extends DataBuffer> fluxBody = Flux.from(body);
     				//(返回数据内如果字符串过大,默认会切割)解决返回体分段传输
     				return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
     					List<String> list = Lists.newArrayList();
     					dataBuffers.forEach(dataBuffer -> {
     						try {
     							byte[] content = new byte[dataBuffer.readableByteCount()];
     							dataBuffer.read(content);
     							DataBufferUtils.release(dataBuffer);
     							list.add(new String(content, "utf-8"));
     						} catch (Exception e) {
     							log.info("加载Response字节流异常,失败原因:{}", Throwables.getStackTraceAsString(e));
     						}
     					});
     					String responseData = joiner.join(list);
    
     					System.out.println("responseData:"+responseData);
    
     					byte[] uppedContent = new String(responseData.getBytes(), Charset.forName("UTF-8")).getBytes();
     					originalResponse.getHeaders().setContentLength(uppedContent.length);
     					return bufferFactory.wrap(uppedContent);
     				}));
     			}
     		}
     		return super.writeWith(Flux.from(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(response).build());
    

    }

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

image

友情提示(为了提高issue处理效率):

  • 未按格式要求发帖,会被直接删掉;
  • 描述过于简单或模糊,导致无法处理的,会被直接删掉;
  • 请自己初判问题描述是否清楚,是否方便我们调查处理;
  • 针对问题请说明是Online在线功能(需说明用的主题模板),还是生成的代码功能;
@miniFrank
Copy link
Contributor

您好,可以参考如下写法试下,主要思路就是正确合并databuffer
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
Flux dataBufferFlux = fluxBody.buffer().map(dataBuffers -> {
DataBuffer join = new DefaultDataBufferFactory().join(dataBuffers);
int length = join.readableByteCount();
byte[] content = new byte[length];
join.read(content);
DataBufferUtils.release(join);
String responseBody = new String(content, StandardCharsets.UTF_8);//MODIFY RESPONSE and Return the Modified response
log.info("requestId: {}, method: {}, url: {}, \nresponse body :{}",
request.getId(),
request.getMethodValue(),
request.getURI(),
responseBody);
return dataBufferFactory.wrap(responseBody.getBytes(StandardCharsets.UTF_8));
})
.switchIfEmpty(Flux.defer(() -> {
System.out.println("Write to database here");
return Flux.just();
}));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants