本文主要是介绍springcloud-gateway网关转换响应数据结构乱码问题处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
参考文章:记一次线上bug排查-----SpringCloud Gateway组件 请求头accept-encoding导致响应结果乱码_springcloud gateway response 响应zip响应乱码-CSDN博客
在上述文章记录请求的headers中携带Accept-Encoding参数乱码问题,主要是字节流被压缩未解压直接转字符导致的,因此需要对字节先解压再转换,最终效果实现代码如下:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.UUID;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
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.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Throwables;import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;@Component
public class CustomConvertResponseFilter implements GlobalFilter, Ordered {public static final Logger logger = LoggerFactory.getLogger(CustomConvertResponseFilter.class);private final static String COVERT_FLAG = "gateway-Covert";@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpResponse response = exchange.getResponse();String trackId = UUID.randomUUID().toString();ServerHttpResponseDecorator responseDecorated = new ServerHttpResponseDecorator(response) {@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {if (body instanceof Flux) {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);DataBufferUtils.release(join);// 释放掉内存String bodyStr = "";boolean gzip = false;HttpHeaders headers = response.getHeaders();List<String> contentEncoding = headers.get("Content-Encoding");if (CollectionUtils.isNotEmpty(contentEncoding) && contentEncoding.contains("gzip")) {gzip = true;}String contentType = headers.getFirst("Content-Type");if (StringUtils.isBlank(contentType) || !contentType.contains("application/json")) {response.getHeaders().add(COVERT_FLAG,"0");return bufferFactory().wrap(content);}try {bodyStr = unzipByte2String(content,gzip);JSONObject jsonObject = JSON.parseObject(bodyStr);jsonObject.put("trackId", trackId);bodyStr = JSON.toJSONString(jsonObject, SerializerFeature.WriteMapNullValue);byte[] respData = string2ZipByte(bodyStr,gzip);getDelegate().getHeaders().setContentLength(respData.length);response.getHeaders().add(COVERT_FLAG,"1");return bufferFactory().wrap(respData);} catch (Exception e) {logger.error("Gateway.CustomConvertResponseFilter发生异常,异常信息:{}", Throwables.getStackTraceAsString(e));}response.getHeaders().add(COVERT_FLAG,"0");return bufferFactory().wrap(content);}));}return super.writeWith(body);}};return chain.filter(exchange.mutate().response(responseDecorated).build());}@Overridepublic int getOrder() {return Ordered.HIGHEST_PRECEDENCE + 10199;}/*** gzip压缩后的字节转String* @param compressed* @return* @throws IOException*/public static String unzipByte2String(byte[] compressed,boolean gzip) throws IOException {if(!gzip){return new String(compressed, StandardCharsets.UTF_8);}// 使用GZIPInputStream解压缩数据ByteArrayInputStream bais = new ByteArrayInputStream(compressed);GZIPInputStream gzis = new GZIPInputStream(bais);ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int len;while ((len = gzis.read(buffer)) != -1) {baos.write(buffer, 0, len);}// 获取解压缩后的字节数组byte[] decompressedData = baos.toByteArray();// 将字节数组转换为字符串(假设内容是UTF-8编码的文本)return new String(decompressedData, StandardCharsets.UTF_8);}/*** String转gzip压缩后的字节* @param json* @return* @throws IOException*/public static byte[] string2ZipByte(String json,boolean gzip) throws IOException {// 将字符串转换为字节数组(使用UTF-8编码)byte[] stringBytes = json.getBytes(StandardCharsets.UTF_8);if(!gzip){return stringBytes;}// 创建一个ByteArrayOutputStream来存储压缩后的数据ByteArrayOutputStream baos = new ByteArrayOutputStream();// 创建一个GZIPOutputStream来压缩数据并写入到baos中GZIPOutputStream gos = new GZIPOutputStream(baos);// 写入字符串的字节到GZIPOutputStream中gos.write(stringBytes);// 完成写入后,关闭GZIPOutputStream以完成压缩过程gos.close();// 获取压缩后的字节数组return baos.toByteArray();}
}
这篇关于springcloud-gateway网关转换响应数据结构乱码问题处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!