簡體   English   中英

我可以將反應器上下文隱式傳遞給 grpc clientInterceptor 嗎?

[英]Can I pass reactor Context into grpc clientInterceptor implicitly?

這是我想在高層次上做的事情

  1. 在 WebFilter 中捕獲一些 http 標頭
  2. 在 Controller 方法中,我進行了 grpc 調用
  3. 我想將 http 標頭作為 grpc 元數據標頭傳播

目前,我的工作實施是

  1. WebFilter 捕獲 http 標頭並寫入反應器上下文
  2. Controller 方法提取反應器上下文並將其傳遞給 Grpc ClientInterceptor
  3. Grpc ClientInterceptor 從 Context 中提取 http 標頭並注入 Grpc 元數據標頭

但我想避免讓 Controller 方法做任何工作(上面的步驟 2)。

這是一個實現,但正在尋找一種方法來獲取 http 標頭到 Grpc 元數據,而無需從 Controller 方法顯式傳遞它們。

網絡過濾器

public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
  return chain.filter(exchange)
    .contextWrite(Context.of("my-header", "header-value"));
}

Controller 方法

@GetMapping
public Mono<String> testHeaderPropagation() throws Exception {
  return Mono.deferContextual(reactorContext -> {
    Response response = grpcStub
      .withInterceptors(new GrpcClientInterceptor(reactorContext))
      .call(request);
    return Mono.just(response.getMessage());
  });
}

GrpcClient攔截器

public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
  final ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);
  return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
    @Override
    public void start(Listener<RespT> responseListener, Metadata headers) {
      Metadata.Key < String > key =
          Metadata.Key.of("filter-context", Metadata.ASCII_STRING_MARSHALLER);
      headers.put(key, context.get("filter-context"));

      delegate().start(responseListener, headers);
    }
  };
}

我想簡化我的 Controller 方法(刪除反應堆上下文的顯式傳入到 clientInterceptor)

grpcStub.call(request)

我相信 Spring Sleuth 有辦法做到這一點,但不確定如何調整其方法。 我錯過了什么聰明的東西?

編輯

我推動包含最少 controller 方法代碼的版本的原因是因為其他開發人員將編寫 controller 和方法。 如果可能的話,我想建立一個不需要額外布線的模式,否則有人可能會忘記這樣做或做錯了。

編輯

后續問題。 我沒有讓 controller 方法將上下文傳遞給 clientInterceptor,而是嘗試在 Grpc ClientInterceptor 中獲取上下文,但這似乎不起作用。

這是我試圖做的

public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
  final ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);

  return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
    @Override
    public void start(Listener<RespT> responseListener, Metadata headers) {

      Mono.deferContextual(context -> {
        Metadata.Key < String > key =
            Metadata.Key.of("CONTEXT-HEADER", Metadata.ASCII_STRING_MARSHALLER);
        headers.put(key, context.get("CONTEXT-HEADER"));

        delegate().start(responseListener, headers);

        return Mono.empty();
      }).subscribe();


    }
  };
}

但我得到一個錯誤

reactor.core.Exceptions$ErrorCallbackNotImplemented:java.util.NoSuchElementException:上下文不包含鍵 CONTEXT-HEADER

試圖理解為什么反應堆管道在這里破裂

我想出了另一個不需要 WebFilter 或反應器上下文的解決方案。 但我仍然更喜歡某種方式來進行“全面自動傳播”。

在這個解決方案中,我只是將注入到 controller 方法中的 ServerWebExchange 傳遞給客戶端攔截器,該攔截器將讀取標頭。

@GetMapping
public Mono<String> testHeaderPropagation(ServerWebExchange exchange) throws Exception {
  MyGrpcStub grpcStubWithInterceptor = attachMetadata(grpcStub, exchange);
  Response response = grpcStub
    .call(request);
  return Mono.just(response.getMessage());
}

public static <S extends AbstractStub<S>> S attachMetadata(S stub, ServerWebExchange exchange) {
  return stub.withInterceptors(new GrpcClientInterceptor(exchange));
}

然后我的新 GrpcClientInterceptor

public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
  HttpHeaders httpHeaders = exchange.getRequest().getHeaders();

  final ClientCall<ReqT, RespT> call = next.newCall(method, callOptions);
  return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(call) {
    @Override
    public void start(Listener<RespT> responseListener, Metadata headers) {
      Metadata.Key < String > key =
          Metadata.Key.of("my-header", Metadata.ASCII_STRING_MARSHALLER);
      headers.put(key, httpHeaders.getFirst("my-header"));

      delegate().start(responseListener, headers);
    }
  };
}

grpc 和 Reactor 互不了解,因此必須有人翻譯兩者之間的上下文信息。 您當前的方法是推薦的方法,即使考慮到 Sleuth(因為Context的全面自動傳播是一個混合包,對性能影響很大)。 這是針對您的確切需求,萬無一失,所以我會保留它。

暫無
暫無

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

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