springcloud gateway 业务系统返回的响应报文内容分段传输导致不全的解决方案

1.我们在实际开发中由网关路由到业务系统处理后返回响应报文。对于返回小内容响应报文通过super.writeWith(fluxBody.map(dataBuffer -> {}))是没有问题的,
但有时业务系统需要返回过大的响应报文的时候就有问题了,fluxBody返回体会存在分段传输,从而导致返回的json报文只有一半,前端无法解析而导致错误。

解决方案如下:
既然返回内容过大存在分段传出,比如json传输了一半,另一半丢失,所以我们需要考虑报文拼装方式,只有报文全部返回才统一返回给前端。
大报文我们需要对fluxBody流循环拼接处理,所以改变方式如下,把fluxBody.map变为fluxBody.buffer().map,从而可以foreach循环Body体了。

代码如下:

public class WrapperResFilter implements GlobalFilter, Ordered {
    
    private static Joiner joiner = Joiner.on("");//将 List 数据以""分隔进行拼接

    @Override
    public int getOrder() {
        return -10;
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取response的 返回数据
        ServerHttpResponse originalResponse = exchange.getResponse();
        HttpHeaders header = originalResponse.getHeaders();
        header.add("Content-Type", "application/json; charset=UTF-8");
        
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                log.info("body:{},getStatusCode():{}",body,getStatusCode());
                if (getStatusCode() != null && getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {//解决返回体分段传输
                        List<String> list = Lists.newArrayList();
                        dataBuffers.forEach(dataBuffer -> {
                            byte[] content = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(content);
                            DataBufferUtils.release(dataBuffer);
                            try {
                                list.add(new String(content, "utf-8"));
                            } catch (Exception e) {
                                log.error("--list.add--error",e);
                            }
                        });
                        String responseData = joiner.join(list);                  
                        String resStr = CommonMethod.resSetResult(responseData);
                        byte[] uppedContent = new String(resStr.getBytes(), Charset.forName("UTF-8")).getBytes();
                        originalResponse.getHeaders().setContentLength(uppedContent.length);
                        return bufferFactory.wrap(uppedContent);

                    }));

              以下省略...

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
如果你想在Spring Cloud Gateway中根据响应内容来判断是否进行转发请求或返回结果,可以使用Spring Cloud Gateway提供的GlobalFilter来实现。 具步骤如下: 1. 在Spring Cloud Gateway中定义一个GlobalFilter,例如: ``` @Component public class MyFilter implements GlobalFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange).then(Mono.fromRunnable(() -> { ServerHttpResponse response = exchange.getResponse(); HttpStatus statusCode = response.getStatusCode(); if (statusCode == HttpStatus.OK) { // 获取响应内容 byte[] bytes = ((DataBuffer) response.getBody()).asByteBuffer().array(); String responseBody = new String(bytes, StandardCharsets.UTF_8); // 判断响应内容是否需要转发请求 if (responseBody.contains("需要转发请求的关键字")) { // 构造新的请求URI URI newUri = UriComponentsBuilder.fromUri(exchange.getRequest().getURI()) .host("newhost") .path("newpath") .build() .toUri(); // 构造新的请求对象 ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build(); // 转发新的请求 chain.filter(exchange.mutate().request(newRequest).build()); } else { // 返回响应内容 response.getHeaders().setContentLength(responseBody.length()); DataBuffer buffer = response.bufferFactory().wrap(responseBody.getBytes(StandardCharsets.UTF_8)); return response.writeWith(Flux.just(buffer)); } } })); } } ``` 这个GlobalFilter会在每个请求响应之后执行,获取响应内容并根据内容判断是否需要转发请求或返回响应内容。 2. 在Spring Cloud Gateway的配置文件中配置这个GlobalFilter,例如: ``` spring: cloud: gateway: default-filters: - MyFilter ``` 这个配置将这个GlobalFilter添加到默认的过滤器列表中,使其在每个请求中都被执行。 注意:这个GlobalFilter的核心逻辑是根据响应内容来判断是否需要转发请求或返回响应内容。如果需要转发请求,可以构造新的请求URI和请求对象,然后使用GatewayFilterChain的filter方法来执行新的请求。如果需要返回响应内容,可以构造一个新的DataBuffer对象,并使用ServerHttpResponse的writeWith方法来返回响应内容
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值