李锋镝的博客 - LiFengdi.Com

  • 首页
  • 时间轴
  • 留言
  • 左邻右舍
  • 我的日常
  • 关于我
青衿之志 履践致远
霁月光风 不萦于怀
  1. 首页
  2. 原创
  3. 正文

从零搭建Spring Cloud Gateway网关(二)—— 打印请求响应日志

2020年3月19日 15289点热度 2人点赞 6条评论

作为网关,日志记录是必不可少的功能,可以在网关出增加requestId来查询整个请求链的调用执行情况等等。

打印请求日志

打印请求日志最重要的就是打印请求参数这些东西,不过RequestBody通常情况下在被读取一次之后就会失效,这样的话,下游的服务就不能正常获取到请求参数了。所以我们需要重写下请求体。

具体方法呢有很多,这里说一下我用的两种:

第一种

代码如下:

package com.lifengdi.gateway.filter;

import com.lifengdi.gateway.constant.HeaderConstant;
import com.lifengdi.gateway.constant.OrderedConstant;
import com.lifengdi.gateway.log.Log;
import com.lifengdi.gateway.log.LogHelper;
import com.lifengdi.gateway.utils.GenerateIdUtils;
import com.lifengdi.gateway.utils.IpUtils;
import io.netty.buffer.UnpooledByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;

/**
 * 请求日志打印
 */
@Component
@Slf4j
public class RequestLogFilter implements GlobalFilter, Ordered {

    @Override
    public int getOrder() {
        return OrderedConstant.REQUEST_FILTER;
    }

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        long startTime = System.currentTimeMillis();
        try {
            ServerHttpRequest request = exchange.getRequest();
            // 设置X-Request-Id
            AtomicReference requestId = new AtomicReference(GenerateIdUtils.requestIdWithUUID());
            Consumer httpHeadersConsumer = httpHeaders -> {
                String headerRequestId = request.getHeaders().getFirst(HeaderConstant.REQUEST_ID);
                if (StringUtils.isBlank(headerRequestId)) {
                    httpHeaders.set(HeaderConstant.REQUEST_ID, requestId.get());
                } else {
                    requestId.set(headerRequestId);
                }
                httpHeaders.set(HeaderConstant.START_TIME_KEY, String.valueOf(startTime));
            };
            ServerRequest serverRequest = ServerRequest.create(exchange,
                    HandlerStrategies.withDefaults().messageReaders());
            URI requestUri = request.getURI();
            String uriQuery = requestUri.getQuery();
            String url = requestUri.getPath() + (StringUtils.isNotBlank(uriQuery) ? "?" + uriQuery : "");
            HttpHeaders headers = request.getHeaders();
            MediaType mediaType = headers.getContentType();
            String method = request.getMethodValue().toUpperCase();

            // 原始请求体
            final AtomicReference requestBody = new AtomicReference();
            final AtomicBoolean newBody = new AtomicBoolean(false);
            if (Objects.nonNull(mediaType) && LogHelper.isUploadFile(mediaType)) {
                requestBody.set("上传文件");
            } else {
                if (method.equals("GET")) {
                    if (StringUtils.isNotBlank(uriQuery)) {
                        requestBody.set(uriQuery);
                    }
                } else {
                    newBody.set(true);
                }
            }
            final Log logDTO = new Log();
            logDTO.setLevel(Log.LEVEL.INFO);
            logDTO.setRequestUrl(url);
            logDTO.setRequestBody(requestBody.get());
            logDTO.setRequestMethod(method);
            logDTO.setRequestId(requestId.get());
            logDTO.setIp(IpUtils.getClientIp(request));

            ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeadersConsumer).build();
            ServerWebExchange build = exchange.mutate().request(serverHttpRequest).build();
            return build.getSession().flatMap(webSession -> {
                logDTO.setSessionId(webSession.getId());
                if (newBody.get() && headers.getContentLength() > 0) {
                    Mono bodyToMono = serverRequest.bodyToMono(String.class);
                    return bodyToMono.flatMap(reqBody -> {
                        logDTO.setRequestBody(reqBody);
                        // 重写原始请求
                        ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
                            @Override
                            public Flux getBody() {
                                NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
                                DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(reqBody.getBytes());
                                return Flux.just(bodyDataBuffer);
                            }
                        };
                        return chain.filter(exchange.mutate()
                                .request(requestDecorator)
                                .build()).then(LogHelper.doRecord(logDTO));
                    });
                } else {
                    return chain.filter(exchange).then(LogHelper.doRecord(logDTO));
                }
            });

        } catch (Exception e) {
            log.error("请求日志打印出现异常", e);
            return chain.filter(exchange);
        }
    }

}

上面的核心代码是:

// 重写原始请求
ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
    @Override
    public Flux getBody() {
        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
        DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(reqBody.getBytes());
        return Flux.just(bodyDataBuffer);
    }
};
return chain.filter(exchange.mutate()
        .request(requestDecorator)
        .build()).then(LogHelper.doRecord(logDTO));

如果不需要对session进行操作,可以直接调用这块就行。

关于请求时间,我这里采用的是将时间戳放进请求头中,等到打印日志的时候再从请求头中读取然后计算出时间。否则如果单独在某个filter中计算请求时间,会造成时间不太准确。当然这样时间也不是很准确,毕竟还有Spring本身的filter等业务逻辑,不过时间相差不是很大,大概十几毫秒的样子。

第二种

第二种就是自己缓存下请求体,读取的时候读取缓存内容。

代码如下:

package com.lifengdi.gateway.log;

import com.lifengdi.gateway.constant.HeaderConstant;
import com.lifengdi.gateway.utils.IpUtils;
import io.netty.buffer.UnpooledByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Objects;

/**
 * 对ServerHttpRequest进行二次封装,解决requestBody只能读取一次的问题
 * @author: Li Fengdi
 * @date: 2020-03-17 18:02
 */
@Slf4j
public class CacheServerHttpRequestDecorator extends ServerHttpRequestDecorator {
    private DataBuffer bodyDataBuffer;
    private int getBufferTime = 0;
    private byte[] bytes;

    public CacheServerHttpRequestDecorator(ServerHttpRequest delegate) {
        super(delegate);
    }

    @Override
    public Flux getBody() {
        if (getBufferTime == 0) {
            getBufferTime++;
            Flux flux = super.getBody();
            return flux.publishOn(Schedulers.single())
                    .map(this::cache)
                    .doOnComplete(() -> trace(getDelegate()));

        } else {
            return Flux.just(getBodyMore());
        }

    }

    private DataBuffer getBodyMore() {
        NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
        bodyDataBuffer = nettyDataBufferFactory.wrap(bytes);
        return bodyDataBuffer;
    }

    private DataBuffer cache(DataBuffer buffer) {
        try {
            InputStream dataBuffer = buffer.asInputStream();
            bytes = IOUtils.toByteArray(dataBuffer);
            NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
            bodyDataBuffer = nettyDataBufferFactory.wrap(bytes);
            return bodyDataBuffer;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private void trace(ServerHttpRequest request) {
        URI requestUri = request.getURI();
        String uriQuery = requestUri.getQuery();
        String url = requestUri.getPath() + (StringUtils.isNotBlank(uriQuery) ? "?" + uriQuery : "");
        HttpHeaders headers = request.getHeaders();
        MediaType mediaType = headers.getContentType();
        String schema = requestUri.getScheme();
        String method = request.getMethodValue().toUpperCase();
        if ((!"http".equals(schema) && !"https".equals(schema))) {
            return;
        }
        String reqBody = null;
        if (Objects.nonNull(mediaType) && LogHelper.isUploadFile(mediaType)) {
            reqBody = "上传文件";
        } else {
            if (method.equals("GET")) {
                if (StringUtils.isNotBlank(uriQuery)) {
                    reqBody = uriQuery;
                }
            } else if (headers.getContentLength() > 0) {
                reqBody = LogHelper.readRequestBody(request);
            }
        }
        final Log logDTO = new Log();
        logDTO.setLevel(Log.LEVEL.INFO);
        logDTO.setRequestUrl(url);
        logDTO.setRequestBody(reqBody);
        logDTO.setRequestMethod(method);
        logDTO.setRequestId(headers.getFirst(HeaderConstant.REQUEST_ID));
        logDTO.setIp(IpUtils.getClientIp(request));
        log.info(LogHelper.toJsonString(logDTO));
    }

}

filter这里就简单写下:

package com.lifengdi.gateway.filter;

import com.lifengdi.gateway.constant.OrderedConstant;
import com.lifengdi.gateway.log.CacheServerHttpRequestDecorator;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * @author: Li Fengdi
 * @date: 2020-03-17 18:17
 */
//@Component
public class LogFilter implements GlobalFilter, Ordered {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        CacheServerHttpRequestDecorator cacheServerHttpRequestDecorator = new CacheServerHttpRequestDecorator(exchange.getRequest());

        return chain.filter(exchange.mutate().request(cacheServerHttpRequestDecorator).build());
    }

    @Override
    public int getOrder() {
        return OrderedConstant.LOGGING_FILTER;
    }
}

工具类也贴下:

package com.lifengdi.gateway.log;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lifengdi.gateway.constant.HeaderConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
public class LogHelper {

    private final static ObjectMapper objectMapper = new ObjectMapper();

    /**
     * Log转JSON
     * @param dto Log
     * @return JSON字符串
     */
    public static String toJsonString(@NonNull Log dto) {
        try {
            return objectMapper.writeValueAsString(dto);
        } catch (JsonProcessingException e) {
            log.error("Log转换JSON异常", e);
            return null;
        }
    }

    /**
     * 根据MediaType获取字符集,如果获取不到,则默认返回UTF_8
     * @param mediaType MediaType
     * @return Charset
     */
    public static Charset getMediaTypeCharset(@Nullable MediaType mediaType) {
        if (Objects.nonNull(mediaType) && mediaType.getCharset() != null) {
            return mediaType.getCharset();
        } else {
            return StandardCharsets.UTF_8;
        }
    }

    /**
     * 记录日志(后期可扩展为通过MQ将日志发送到ELK系统)
     * @param dto Log
     * @return Mono.empty()
     */
    public static Mono doRecord(Log dto) {
        log.info(toJsonString(dto));
        return Mono.empty();
    }

    /**
     * 从HttpHeaders获取请求开始时间
     * 

* 要求请求头中必须要有参数{@link HeaderConstant#START_TIME_KEY},否则将返回当前时间戳 *

* @param headers HttpHeaders请求头 * @return 开始时间时间戳(Mills) */ public static long getStartTime(HttpHeaders headers) { String startTimeStr = headers.getFirst(HeaderConstant.START_TIME_KEY); return StringUtils.isNotBlank(startTimeStr) ? Long.parseLong(startTimeStr) : System.currentTimeMillis(); } /** * 根据HttpHeaders请求头获取请求执行时间 *

* 要求请求头中必须要有参数{@link HeaderConstant#START_TIME_KEY} *

* @param headers HttpHeaders请求头 * @return 请求执行时间 */ public static long getHandleTime(HttpHeaders headers) { String startTimeStr = headers.getFirst(HeaderConstant.START_TIME_KEY); long startTime = StringUtils.isNotBlank(startTimeStr) ? Long.parseLong(startTimeStr) : System.currentTimeMillis(); return System.currentTimeMillis() - startTime; } /** * 读取请求体内容 * @param request ServerHttpRequest * @return 请求体 */ public static String readRequestBody(ServerHttpRequest request) { HttpHeaders headers = request.getHeaders(); MediaType mediaType = headers.getContentType(); String method = request.getMethodValue().toUpperCase(); if (Objects.nonNull(mediaType) && mediaType.equals(MediaType.MULTIPART_FORM_DATA)) { return "上传文件"; } else { if (method.equals("GET")) { if (!request.getQueryParams().isEmpty()) { return request.getQueryParams().toString(); } return null; } else { AtomicReference bodyString = new AtomicReference(); request.getBody().subscribe(buffer -> { byte[] bytes = new byte[buffer.readableByteCount()]; buffer.read(bytes); DataBufferUtils.release(buffer); bodyString.set(new String(bytes, getMediaTypeCharset(mediaType))); }); return bodyString.get(); } } } /** * 判断是否是上传文件 * @param mediaType MediaType * @return Boolean */ public static boolean isUploadFile(@Nullable MediaType mediaType) { if (Objects.isNull(mediaType)) { return false; } return mediaType.equals(MediaType.MULTIPART_FORM_DATA) || mediaType.equals(MediaType.IMAGE_GIF) || mediaType.equals(MediaType.IMAGE_JPEG) || mediaType.equals(MediaType.IMAGE_PNG) || mediaType.equals(MediaType.MULTIPART_MIXED); } }

打印响应报文

响应报文需要在Spring重写了响应体之后才能获取到,所以对filter的执行顺序有要求,需要在
NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER之前执行。代码如下:

package com.lifengdi.gateway.filter;

import com.lifengdi.gateway.constant.HeaderConstant;
import com.lifengdi.gateway.constant.OrderedConstant;
import com.lifengdi.gateway.log.Log;
import com.lifengdi.gateway.log.LogHelper;
import com.lifengdi.gateway.utils.IpUtils;
import io.netty.buffer.UnpooledByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.charset.Charset;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 请求响应日志打印
 */
@Component
@Slf4j
public class ResponseLogFilter implements GlobalFilter, Ordered {

    @Override
    public int getOrder() {
        return OrderedConstant.LOGGING_FILTER;
    }

    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        try {
            ServerHttpRequest request = exchange.getRequest();
            ServerRequest serverRequest = ServerRequest.create(exchange,
                    HandlerStrategies.withDefaults().messageReaders());
            URI requestUri = request.getURI();
            String uriQuery = requestUri.getQuery();
            HttpHeaders headers = request.getHeaders();
            MediaType mediaType = headers.getContentType();
            String schema = requestUri.getScheme();
            String method = request.getMethodValue().toUpperCase();

            // 只记录http、https请求
            if ((!"http".equals(schema) && !"https".equals(schema))) {
                return chain.filter(exchange);
            }
            final AtomicReference requestBody = new AtomicReference();// 原始请求体
            // 排除流文件类型,比如上传的文件contentType.contains("multipart/form-data")
            if (Objects.nonNull(mediaType) && LogHelper.isUploadFile(mediaType)) {
                requestBody.set("上传文件");
                return chain.filter(exchange);
            } else {
                if (method.equals("GET")) {
                    if (StringUtils.isNotBlank(uriQuery)) {
                        requestBody.set(uriQuery);
                    }
                } else if (headers.getContentLength() > 0){
                    return serverRequest.bodyToMono(String.class).flatMap(reqBody -> {
                        requestBody.set(reqBody);
                        // 重写原始请求
                        ServerHttpRequestDecorator requestDecorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
                            @Override
                            public HttpHeaders getHeaders() {
                                HttpHeaders httpHeaders = new HttpHeaders();
                                httpHeaders.putAll(super.getHeaders());
                                return httpHeaders;
                            }

                            @Override
                            public Flux getBody() {
                                NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(new UnpooledByteBufAllocator(false));
                                DataBuffer bodyDataBuffer = nettyDataBufferFactory.wrap(reqBody.getBytes());
                                return Flux.just(bodyDataBuffer);
//                                return Flux.just(reqBody).map(bx -> exchange.getRequest().bufferFactory().wrap(bx.getBytes()));
                            }
                        };
                        ServerHttpResponseDecorator responseDecorator = getServerHttpResponseDecorator(exchange,
                                requestBody);
                        return chain.filter(exchange.mutate()
                                .request(requestDecorator)
                                .response(responseDecorator)
                                .build());
                    });
                }
                ServerHttpResponseDecorator decoratedResponse = getServerHttpResponseDecorator(exchange,
                        requestBody);
                return chain.filter(exchange.mutate()
                        .response(decoratedResponse)
                        .build());
            }

        } catch (Exception e) {
            log.error("请求响应日志打印出现异常", e);
            return chain.filter(exchange);
        }

    }

    private ServerHttpResponseDecorator getServerHttpResponseDecorator(ServerWebExchange exchange,
                                                                       AtomicReference requestBody) {
        // 获取response的返回数据
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();
        HttpStatus httpStatus = originalResponse.getStatusCode();
        ServerHttpRequest request = exchange.getRequest();
        URI requestUri = request.getURI();
        String uriQuery = requestUri.getQuery();
        String url = requestUri.getPath() + (StringUtils.isNotBlank(uriQuery) ? "?" + uriQuery : "");
        HttpHeaders headers = request.getHeaders();
        String method = request.getMethodValue().toUpperCase();
        String requestId = headers.getFirst(HeaderConstant.REQUEST_ID);

        // 封装返回体
        return new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono writeWith(Publisher extends DataBuffer> body) {
                if (body instanceof Flux) {
                    Flux extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                        DataBuffer join = bufferFactory.join(dataBuffers);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);
                        DataBufferUtils.release(join);
                        Charset charset = LogHelper.getMediaTypeCharset(originalResponse.getHeaders().getContentType());
                        String responseBody = new String(content, charset);

                        long handleTime = LogHelper.getHandleTime(headers);
                        Log logDTO = new Log(Log.TYPE.RESPONSE);
                        logDTO.setLevel(Log.LEVEL.INFO);
                        logDTO.setRequestUrl(url);
                        logDTO.setRequestBody(requestBody.get());
                        logDTO.setResponseBody(responseBody);
                        logDTO.setRequestMethod(method);
                        if (Objects.nonNull(httpStatus)) {
                            logDTO.setStatus(httpStatus.value());
                        }
                        logDTO.setHandleTime(handleTime);
                        logDTO.setRequestId(requestId);
                        logDTO.setIp(IpUtils.getClientIp(request));
                        exchange.getSession().subscribe(webSession -> {
                            logDTO.setSessionId(webSession.getId());
                        });

                        log.info("url:{},method:{},请求内容:{},响应内容:{},status:{},handleTime:{},requestId:{}",
                                url, method, requestBody.get(), responseBody, httpStatus,
                                handleTime, requestId);
                        log.info(LogHelper.toJsonString(logDTO));
                        return bufferFactory.wrap(content);
                    }));
                }
                return super.writeWith(body);
            }
        };
    }

}

代码已上传到git上,需要的可以去看看。

git代码地址:https://github.com/lifengdi/spring-cloud-gateway-demo

除非注明,否则均为李锋镝的博客 - LiFengdi.Com原创文章,转载必须以链接形式标明本文链接
本文链接:https://www.lifengdi.com/archives/article/1778
本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: JAVA Spring Cloud Spring Cloud Gateway SpringBoot 网关
最后更新:2021年1月6日

李锋镝

既然选择了远方,便只顾风雨兼程。

打赏 点赞
< 上一篇
下一篇 >
guest
您的姓名(必填)
您的邮箱(必填)
您的站点
guest
您的姓名(必填)
您的邮箱(必填)
您的站点
6 评论
最热
最新 最旧
Inline Feedbacks
查看所有评论
xiaowang
xiaowang
VIP
2020年7月21日 15:27

重写原始请求的时候,没有加入设置的headers信息,导致resp里面获取不到requestid。还请博主确认下是不是有错误。我在重写请求加入了以后resp就可以获取到requestid了。

0
0
回复
李锋镝
李锋镝
博主
回复  xiaowang
2020年7月21日 18:00

@xiaowang 我在本地测试了下 并没有你说的问题。。
PostMan请求:

curl --location --request GET 'localhost:8080/jar/test/test' \
--header 'requestid: 123'

服务端打印请求头:

requestid:123
user-agent:PostmanRuntime/7.26.1
accept:*/*
postman-token:fd34e9e4-bd78-441e-84e8-c8b55e8ff672
accept-encoding:gzip, deflate, br
x-request-id:176026888f2941a8b8665a47e978d0ba
x-st:1595325030530
forwarded:proto=http;host="localhost:8080";for="0:0:0:0:0:0:0:1:61784"
x-forwarded-for:0:0:0:0:0:0:0:1
x-forwarded-proto:http
x-forwarded-port:8080
x-forwarded-host:localhost:8080
host:localhost:8081
content-length:0
0
0
回复
古月
古月
VIP
2021年5月27日 16:13

我测试了一下,发现添加这些过滤器以后,gateway转发的性能降低了很多!

0
-1
回复
李锋镝
李锋镝
博主
回复  古月
2021年5月27日 16:58

@古月 这个问题确实存在,毕竟中间多了这么一层,而且对于请求的解析还挺耗费时间和资源的…… :douyin.44:

0
0
回复
lipor
lipor
VIP
2020年10月12日 10:36
您好,我写了个很普通的get请求,就输出一句话,可是并没有打印日志,断点打在了RequestLogFilterye也没有被拦截
0
-1
回复
李锋镝
李锋镝
博主
回复  lipor
2020年10月12日 13:41

@lipor 网关的配置贴一下看看

0
0
回复
支付宝红包

王师北定中原日,家祭无忘告乃翁。

最新 热点 随机
最新 热点 随机
回忆是一条没有尽头的路 这样的日子什么时候才是个头 MySQL 中的 distinct 和 group by 哪个效率更高? 开工啦~ 今晚,回家过年! 图数据库选型:Neo4j、Janus、HugeGraph
看病难~取药难~~阳了...开工啦~RocketMQ的push消费方式实现详解国庆节过的也很累~~MybatisCodeHelperPro激活
MySQL 中的 distinct 和 group by 哪个效率更高? docker registry私库镜像删除 Redisson分布式锁的watch dog自动续期机制 JVM安全点介绍 SpringBoot整合GraphQL入门教程 不慌不忙的坚强(林徽因39段最美文字!)
最近评论
李锋镝 发布于 2 周前(03月10日) 已添加~欢迎回访喔
博客录(boke.lu) 发布于 2 周前(03月10日) 已添加贵站0.0 名称:博客录(boke.lu) 简介:boke.lu · 博客收录展示平台~ 链接...
李锋镝 发布于 3 周前(03月05日) 系统版本是win11吗?
HJQ 发布于 4 周前(02月28日) 同问,注册表都没有楼主说的值。
林羽凡 发布于 1 个月前(02月16日) 开工大吉。
有情链接
  • 志文工作室
  • 临窗旋墨
  • 旧时繁华
  • 城南旧事
  • 强仔博客
  • 林三随笔
  • 徐艺扬的博客
  • 云辰博客
  • 韩小韩博客
  • 知向前端
  • 阿誉的博客
  • 林羽凡
  • 情侣头像
  • 哥斯拉
  • 博客录

COPYRIGHT © 2022 lifengdi.com. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang

豫ICP备16004681号-2