簡體   English   中英

如何在 X-Ray SegmentListener 中訪問傳入的 HTTP 請求?

[英]How to access incoming HTTP requests in X-Ray SegmentListener?

問題

我對 Java 使用AWS X-Ray SDK來為我的 Spring Boot 微服務啟用 X-Ray 跟蹤。 通過以下代碼片段,我可以附加自定義SegmentListener

final AWSXRayRecorder recorder = AWSXRayRecorderBuilder
                .standard()
                .withPlugin(new EcsPlugin())
                .withSegmentListener(new SLF4JSegmentListener())
                .withSegmentListener(new MyHttpHeaderSegementListener())
                .build();
AWSXRay.setGlobalRecorder(recorder);

MyHttpHeaderSegementListener ,我嘗試根據傳入的 HTTP 請求 header(來自前端)注入 X-Ray 注釋:


public class MyHttpHeaderSegementListener implements SegmentListener {

  // snippet source: https://stackoverflow.com/a/54349178/6489012
  public static Optional<HttpServletRequest> getCurrentHttpRequest() {
    return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                   .filter(ServletRequestAttributes.class::isInstance)
                   .map(ServletRequestAttributes.class::cast)
                   .map(ServletRequestAttributes::getRequest);
  }

  public MyHttpHeaderSegementListener() {}

  @Override
  public void onBeginSegment(final Segment segment) {
    final var httpContext = MyHttpHeaderSegementListener.getCurrentHttpRequest();
    httpContext.ifPresent(context -> segment.putAnnotation("Origin", context.getHeader("Origin")));
  }

}

段偵聽器按預期觸發onBeginSegment段,但MyHttpHeaderSegementListener.getCurrentHttpRequest()始終返回Optional.empty

問題

  1. 是否有可能在SegmentListener中檢查傳入的 HTTP 請求(因為它們是由Controller接收的)?
  2. aws-xray-sdk-java甚至可能支持原生方式嗎?
  3. 為什么從RequestContextHolder中取出來的請求總是空的?

(有點題外話,但是:4.根據 HTTP 標頭設置注釋甚至是一個好習慣)

我對 2. 和 3. 問題沒有答案,但我找到了 1. 問題的答案。

對於傳入請求,您需要添加一個 Spring 過濾器來配置 AWS X-Ray 由於過濾器可以訪問 HTTP 請求,我只是將自己的過濾器包裝在 AWS 的com.amazonaws.xray.javax.servlet.AWSXRayServletFilter周圍:

public class XRayServletFilter extends AWSXRayServletFilter {
  public XRayServletFilter(String fixedSegmentName) {
    super(fixedSegmentName);
  }

  @Override
  public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
    this.addHttpRequestToContext(request);

    super.doFilter(request, response, chain);
  }

  private void addHttpRequestToContext(final ServletRequest request){
    final Optional<HttpServletRequest> httpServletRequest = HttpRequestUtils.castToHttpRequest(request);

    if (httpServletRequest.isPresent()) {
      final ServletRequestAttributes requestAttributes = new ServletRequestAttributes(httpServletRequest.get());
      RequestContextHolder.setRequestAttributes(requestAttributes);
    }
  }
}

其中使用了我寫的 static class:

public final class HttpRequestUtils {
  public static Optional<HttpServletRequest> getCurrentHttpRequest() {
    return Optional.ofNullable(RequestContextHolder.getRequestAttributes())
                   .filter(ServletRequestAttributes.class::isInstance)
                   .map(ServletRequestAttributes.class::cast)
                   .map(ServletRequestAttributes::getRequest);
  }

  public static Optional<HttpServletRequest> castToHttpRequest(ServletRequest request) {
    try {
      return Optional.of((HttpServletRequest) request);
    } catch (ClassCastException classCastException) {
      return Optional.empty();
    }
  }
}

這個自定義過濾器基本上在 RequestContextHolder 中設置了RequestContextHolder請求。 之后,您可以在您的分段偵聽器中使用它:

public class MyHttpHeaderSegementListener implements SegmentListener {
  public MyHttpHeaderSegementListener() {}

  @Override
  public void onBeginSegment(final Segment segment) {
    final Optional<HttpServletRequest> request = HttpRequestUtils.getCurrentHttpRequest();

    request.map(req -> req.getHeader("Origin")).ifPresent(origin -> segment.putAnnotation("client_origin", origin));;
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM