• WebFlux(reactor)中获取完整response body数据


    场景
    使用Spring Cloud Gateway(SCG)时,想在网关日志中输出返回日志,但由于数据流只能被读取一次,必须使用特定方式进行重写才能正常返回到前端。

    处理过程
    起初使用fluxBody.map读取数据流,会出现多次输出的情况,由于使用的时reactor框架处理数据,导致会出现将一个结果集分为多次处理,会执行多次map,效果不理想。
    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
    Mono<Void> newMono = super.writeWith(
    fluxBody.map(dataBuffer -> {
    String respBody = dataBuffer.toString(StandardCharsets.UTF_8);
    if (respBody.length() > maxLogLength) {
    respBody = respBody.substring(0, maxLogLength);
    }
    if (PathUtil.checkPath(request.getPath().value(), contentLengthUrls)) {
    httpHeaders.setContentLength(respBody.length());
    }
    //匹配是否需要生成slat
    if (PathUtil.checkPath(request.getPath().value(), loginUrls)) {
    String salt = createSlat(JSON.parseObject(respBody).getString("token"));
    if (StringUtils.isEmpty(salt)) {
    logger.warn("CreateSalt error:id={}", request.getHeaders().getFirst(HEADER_REQUEST_ID));
    } else {
    httpHeaders.add("s", salt);
    }
    }
    logger.info("fgwResponse : id={},body = {}", request.getHeaders().getFirst(HEADER_REQUEST_ID), respBody);
    return bufferFactory.wrap(content);
    })
    );
    //request中有salt则返回到response中
    logger.info("fgwResponse : id={},resp = {}", request.getHeaders().getFirst(HEADER_REQUEST_ID), JSON.toJSONString(exchange.getResponse()));
    return newMono;
    最后查看github上的讨论,开发者给出DataBufferUtils.join(body) .doOnNext的方式。
    @Component
    public class LogRespFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpResponse originalResponse = exchange.getResponse();
    ServerHttpRequest request = exchange.getRequest();
    ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
    @Override
    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
    //修改header
    HttpHeaders httpHeaders = originalResponse.getHeaders();
    httpHeaders.add("xxxxxx","aaaaaa");
    //输出返回结果
    if (body instanceof Flux) {
    Mono<Void> newMono = super.writeWith(
    DataBufferUtils.join(body)
    .doOnNext(dataBuffer -> {
    String respBody = dataBuffer.toString(StandardCharsets.UTF_8);
    //输出body
    logger.info("fgwResponse : body = {}", respBody);
    })
    );
    //输出response,不包含body
    logger.info("fgwResponse : resp = {}", JSON.toJSONString(exchange.getResponse()));
    return newMono;

    }
    return super.writeWith(body);
    }
    };
    return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
    }

    ————————————————
    版权声明:本文为CSDN博主「lizz666」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lizz861109/article/details/106303929

  • 相关阅读:
    [zt]活法
    Oracle: wmsys.wm_concat、sys_connect_by_path、自定义函数实现行列转换
    主题:福布斯中文网的一篇关于 宽带山男和篱笆女的文章
    Oracle:指定时间范围内的周分组输出.
    Oracle:查看表空间使用情况.
    Oracle:SQL优化基本步骤
    .NET调用ORACLE存储过程使用数组参数
    CTM CJQ高手指点怎么输出手法
    Oracle:DBMS_RANDOM.VALUE取随机数.
    ASPNET:DateFormatString详解
  • 原文地址:https://www.cnblogs.com/duanxz/p/14829965.html
Copyright © 2020-2023  润新知