Spring Cloud 学习笔记六:搭建微服务工程之Zuul 请求响应信息输出

目录

Zuul 请求响应信息输出


Zuul 请求响应信息输出

系统在生产环境出现问题时,排查问题最好的方式就是查看日志了,日志的记录尽量详细,这样你才能快速定位问题。

下面带大家学习如何在 Zuul 中输出请求响应的信息来辅助我们解决一些问题。

熟悉 Zuul 的朋友都知道,Zuul 中有 4 种类型过滤器,每种都有特定的使用场景,要想记录响应数据,那么必须是在请求路由到了具体的服务之后,返回了才有数据,这种需求就适合用 post 过滤器来实现了。代码如下所示:

@Component
public class PostFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "post";
    }
    @Override
    public int filterOrder() {
        return 100;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        HttpServletRequest req = (HttpServletRequest) RequestContext.getCurrentContext().getRequest();
        System.err.println("REQUEST:: " + req.getScheme() + " " + req.getRemoteAddr() + ":" + req.getRemotePort());
        StringBuilder params = new StringBuilder("?");
        // 获取URL参数
        Enumeration<String> names = req.getParameterNames();
        if (req.getMethod().equals("GET")) {
            while (names.hasMoreElements()) {
                String name = (String) names.nextElement();
                params.append(name);
                params.append("=");
                params.append(req.getParameter(name));
                params.append("&");
            }
        }
        if (params.length() > 0) {
            params.delete(params.length() - 1, params.length());
        }
        System.err.println(
                "REQUEST:: > " + req.getMethod() + " " + req.getRequestURI() + params + " " + req.getProtocol());
        Enumeration<String> headers = req.getHeaderNames();
        while (headers.hasMoreElements()) {
            String name = (String) headers.nextElement();
            String value = req.getHeader(name);
            System.err.println("REQUEST:: > " + name + ":" + value);
        }
        final RequestContext ctx = RequestContext.getCurrentContext();
        // 获取请求体参数
        if (!ctx.isChunkedRequestBody()) {
            ServletInputStream inp = null;
            try {
                inp = ctx.getRequest().getInputStream();
                String body = null;
                if (inp != null) {
                    body = IOUtils.toString(inp);
                    System.err.println("REQUEST:: > " + body);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}

输出效果如图所示:

请求响应信息

获取响应内容的第一种方式,代码如下所示:

        try {
            Object zuulResponse = RequestContext.getCurrentContext().get("zuulResponse");
            if (zuulResponse != null) {
                RibbonHttpResponse resp = (RibbonHttpResponse) zuulResponse;
                String body = IOUtils.toString(resp.getBody());
                System.err.println("RESPONSE:: > " + body);
                resp.close();
                RequestContext.getCurrentContext().setResponseBody(body);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

 获取响应内容的第二种方式,代码如下所示:

		InputStream stream = RequestContext.getCurrentContext().getResponseDataStream();
        if (stream != null) {
            String body = io.micrometer.core.instrument.util.IOUtils.toString(stream);
            System.err.println("RESPONSE:: > " + body);
            RequestContext.getCurrentContext().setResponseBody(body);
        }

为什么上面两种方式可以取到响应内容?

RibbonRoutingFilter 中可以看到下面一段代码,代码如下所示:

public Object run() {
   RequestContext context = RequestContext.getCurrentContext();
   this.helper.addIgnoredHeaders();
   try {
      RibbonCommandContext commandContext = buildCommandContext(context);
      ClientHttpResponse response = forward(commandContext);
      setResponse(response);
      return response;
   }
   catch (ZuulException ex) {
      throw new ZuulRuntimeException(ex);
   }
   catch (Exception ex) {
      throw new ZuulRuntimeException(ex);
   }
}

forward() 方法对服务调用,拿到响应结果,通过 setResponse() 方法进行响应的设置,代码如下所示:

protected void setResponse(ClientHttpResponse resp)
      throws ClientException, IOException {
   RequestContext.getCurrentContext().set("zuulResponse", resp);
   this.helper.setResponse(resp.getRawStatusCode(), resp.getBody(),
         resp.getHeaders());
}

上面第一行代码就可以解释我们的第一种获取的方法,这里直接把响应内容加到了 RequestContext 中。

第二种方式的解释就在 helper.setResponse的逻辑里面了,代码如下所示:

public void setResponse(int status, InputStream entity,
      MultiValueMap<String, String> headers) throws IOException {
   RequestContext context = RequestContext.getCurrentContext();
   context.setResponseStatusCode(status);
   if (entity != null) {
      context.setResponseDataStream(entity);
   }
   // .....
}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

stary1993

你的鼓励是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值