![](/img/trans.png)
[英]Why does my Grpc ClientInterceptor not have the right reactor Context?
[英]Can I pass reactor Context into grpc clientInterceptor implicitly?
這是我想在高層次上做的事情
目前,我的工作實施是
但我想避免讓 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.