Spring Cloud Gateway 3 全局过滤器中修改响应体案例 2

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import lombok.extern.slf4j.Slf4j;
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.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
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 reactor.util.annotation.NonNull;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

@Component
@Slf4j
public class GatewayGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        final long startTime = System.currentTimeMillis();
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        mutate.headers(x -> {
            x.remove(Constant.XXXX_USER_INFO_HEADER_NAME);
            x.remove(Constant.XXXX_FORWARD_SOURCE_HEADER_NAME);
        });
        mutate.header(Constant.XXXX_FORWARD_SOURCE_HEADER_NAME, ForwardSourceEnum.Gateway.getSource());

        ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
            @NonNull
            @Override
            public Mono<Void> writeWith(@NonNull Publisher<? extends DataBuffer> body) {
                String uri = exchange.getRequest().getURI().getPath();

                if (body instanceof Flux) {
                    @SuppressWarnings("unchecked")
                    Flux<? extends DataBuffer> fluxDataBuffer = (Flux<? extends DataBuffer>) body;
                    //此处异常报错并不会打印日志,直接就fallback了
                    return super.writeWith(fluxDataBuffer.buffer()
                        .map(dataBuffer -> {
                                HttpStatus statusCode = this.getStatusCode();
                                DataBuffer responseBody = this.bufferFactory().join(dataBuffer);
                                UserInfo userInfo = Optional.ofNullable((UserInfo) exchange.getAttributes().get(Constant.XXXX_USER_INFO_HEADER_NAME))
                                    .orElse(new UserInfo(false));
                                String ip = userInfo.getIp();
                                String uid = userInfo.getUid();
                                if (statusCode == null || statusCode.isError()) {
                                    log.info("响应uri:{},耗时:{},uid:{},ip:{},内部服务异常响应:{}", uri,
                                        System.currentTimeMillis() - startTime, uid, ip, StandardCharsets.UTF_8.decode(responseBody.asByteBuffer()));
                                    ReturnModelEnum returnModelEnum = (statusCode != null && statusCode.is4xxClientError())
                                        ? ReturnModelEnum.NOT_FOUND_PATH : ReturnModelEnum.ERROR;
                                    responseBody = this.bufferFactory().wrap(JSON.toJSONBytes(ReturnModel.fail(returnModelEnum), JSONWriter.Feature.WriteMapNullValue));
                                    this.setStatusCode(HttpStatus.OK);
                                    this.getHeaders().setContentType(MediaType.APPLICATION_JSON);
                                }
                                MediaType contentType = this.getHeaders().getContentType();
                                long l = System.currentTimeMillis() - startTime;
                                if (contentType == null) {
                                    log.info("响应uri:{},耗时:{},uid:{},ip:{},响应不打印响应体,contentType:null", uri, l, uid, ip);
                                    return responseBody;
                                }
                                String contentTypeString = contentType.toString();
                                if (contentTypeString.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
                                    log.info("响应uri:{},耗时:{},uid:{},ip:{},响应体:{}", uri, l, uid, ip, StandardCharsets.UTF_8.decode(responseBody.asByteBuffer()));
                                } else {
                                    log.info("响应uri:{},耗时:{},uid:{},ip:{},响应体类型:{},不打印响应体", uri, l, uid, ip, contentTypeString);
                                }
                                return responseBody;
                            }
                        )
                    );
                }

                Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                    DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                    DataBuffer dataBuffer = dataBufferFactory.join(dataBuffers);
                    log.info("响应uri:{},耗时:{},响应体:{}", uri, System.currentTimeMillis() - startTime, StandardCharsets.UTF_8.decode(dataBuffer.asByteBuffer()));
                    return this.bufferFactory().wrap(dataBuffer.asByteBuffer());
                }));
            }
        };

        ServerWebExchange newExchange = exchange.mutate().request(request).response(responseDecorator).build();
        return chain.filter(newExchange)
            .then(Mono.fromRunnable(() -> {
                newExchange.getAttributes().clear();
            }));
    }

    @Override
    public int getOrder() {
        return -1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值