spring cloud gateway 统一响应结果

网上较多资料的处理方案是如下:(https://blog.csdn.net/tianyaleixiaowu/article/details/83618037)

import org.reactivestreams.Publisher;
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.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
 
import java.nio.charset.Charset;
 
/**
 * @author wuweifeng wrote on 2018/10/31.
 */
@Component
public class WrapperResponseGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public int getOrder() {
        // -1 is response write filter, must be called before that
        return -2;
    }
 
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
                    return super.writeWith(fluxBody.map(dataBuffer -> {
                        // probably should reuse buffers
                        byte[] content = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(content);
                        //释放掉内存
                        DataBufferUtils.release(dataBuffer);
                        String s = new String(content, Charset.forName("UTF-8"));
                        //TODO,s就是response的值,想修改、查看就随意而为了
                        byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();
                        return bufferFactory.wrap(uppedContent);
                    }));
                }
                // if body is not a flux. never got there.
                return super.writeWith(body);
            }
        };
        // replace response with decorator
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
}

以上处理当服务提供方返回参数为空时,无法正常的构建统一的返回结果.如下:

@PutMapping(value="/user")
    public void update(){
         
    }

但是在前端处理时,只能收到响应200结果状态

PostMan 响应截图
在应用过程中前端都是对结果进行统一拦截处理,希望返回标准化的结果,如图(结果格式自行定义,小生使用的是CODE,MSG,DATA的格式)
有数据时

{
    "data": {
        "token":  “”
    },
    "code": 0,
    "message": "success"
}

无数据时

{

    "code": 0,
    "message": "success"
}

但是在资料中面对这种情况 是无法接达到预期结果,
官方提供了一个ModifyResponseBodyGatewayFilterFactory,可以简单快速的对response进行修改,但是也会遇到以上的问题

最后基于继承ServerHttpResponseDecorator 的方法进行了一些调整达到了目的。

import org.reactivestreams.Publisher;
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.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

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

/**
 * Created by Zone 
 */
public class CommonResponseDecorator extends ServerHttpResponseDecorator {

    private DataBufferFactory bufferFactory ;
    public CommonResponseDecorator(ServerHttpResponse delegate) {
        super(delegate);
        this.bufferFactory = delegate.bufferFactory();
    }

    @Override
    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
        if (body instanceof Flux) {
            Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
            if(this.getDelegate().getHeaders().getContentLength()<1){
                ResponseVo response = new ResponseVo();
                response.setCode(0);
                response.setMessage("success");
                byte[] resp = BeanMapper.toJsonString(response).getBytes(Charset.forName("UTF-8"));
                this.getDelegate().getHeaders().setContentLength(resp.length);

                return getDelegate().writeWith(Flux.just(bufferFactory.wrap(resp)));
            }
            return super.writeWith(fluxBody.map(dataBuffer -> {
                // probably should reuse buffers
                byte[] content = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(content);
                // 释放掉内存
                DataBufferUtils.release(dataBuffer);
                String rs = new String(content, Charset.forName("UTF-8"));
                ResponseVo response = new ResponseVo();
                response.setCode(0);
                response.setMessage("success");
                response.setData(BeanMapper.parseJson(rs,Map.class));
                byte[] newRs = BeanMapper.toJsonString(response).getBytes(Charset.forName("UTF-8"));
                this.getDelegate().getHeaders().setContentLength(newRs.length);//如果不重新设置长度则收不到消息。
                return bufferFactory.wrap(newRs);
            }));
        }
        return super.writeWith(body);
    }
}
/**
 * Created by Zone 
 */
public class WrapperResponseFilter implements GlobalFilter, Ordered {

    @Override
    public int getOrder() { 
        return -2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpResponse originalResponse = exchange.getResponse();
        ServerHttpResponseDecorator decoratedResponse = new CommonResponseDecorator(originalResponse);
        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
}

本人对flux 机制不是特别了解,在识别响应结果是否为空时通过response的ContentLength长度进行识别
运行后结果如下
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐