I am writing a gRPC server side interceptor in java. I simplely want to access the request message and read one field from the message. But after 1 day of googling and talking with others, I couldn't find how to do it.
Any idea how to do it?
import io.grpc.Metadata;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
public class EventInterceptor implements ServerInterceptor {
#Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> serverCall,
Metadata metadata,
ServerCallHandler<ReqT, RespT> serverCallHandler) {
// TODO: Get the request message here
return serverCallHandler.startCall(serverCall, metadata);
}
}
The request message arrives later. You need to return your own listener to observe the message.
import io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener;
public class EventInterceptor implements ServerInterceptor {
#Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> serverCall,
Metadata metadata,
ServerCallHandler<ReqT, RespT> serverCallHandler) {
ServerCall.Listener listener = serverCallHandler.startCall(serverCall, metadata);
return new SimpleForwardingServerCallListener<ReqT>(listener) {
#Override public void onMessage(ReqT req) {
// You now have access to the request(s)
doWork(req);
super.onMessage(req);
}
};
}
}
Related
I have a MessageHandler to receive WebSocket message, and I want resend the message to some restcontrollers. Message has type and content fields, I want to treat them as PostMapping and RequestBody. Is this possible?
public class MessageHandler extends TextWebSocketHandler {
#Override
public void handleTextMessage(#Nonnull final WebSocketSession session, #Nonnull final TextMessage message) {
// parse message and send to restcontroller
}
}
public class WsMessage {
public int type;
public String content;
}
I have ServerInterceptor implementation as follows:
public class MyInterceptor implements ServerInterceptor {
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
final ServerCall<ReqT, RespT> serverCall,
final Metadata headers,
final ServerCallHandler<ReqT, RespT> serverCallHandler) {
System.out.println("Call started");
return new ForwardingServerCallListener.SimpleForwardingServerCallListener<ReqT>(serverCallHandler.startCall(serverCall, headers)) {
public void onMessage(ReqT message) {
System.out.println("onMessage");
super.onMessage(message);
}
public void onCancel() {
System.out.println("onCancel");
super.onCancel();
}
public void onComplete() {
System.out.println("onComplete");
super.onComplete();
};
}
}
I am expecting that for a bidirectional streaming API call, I'll see one "Call Started", multiple "onMessage" (depending on the number of requests in the stream) and one of either "onComplete" or "onCancel".
Similarly for unary API call, I am expecting one each of "Call Started", "onMessage" and "onComplete/onCancel" per call.
Is that correct?
That's correct.
The event order of method you can reference this picture:
You can read this note for more detail: https://helloworlde.github.io/2021/02/20/gRPC-%E6%9C%8D%E5%8A%A1%E9%97%B4%E8%B0%83%E7%94%A8%E4%BA%8B%E4%BB%B6%E6%B5%81%E7%A8%8B/
I have a middleware and I load user data (DealerId) from the database and add it to the context.items to be able to access DealerId in all my actions later on.
here is my middleware:
public class LoadUserData
{
private readonly RequestDelegate _next;
public LoadUserData(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context, UserManager<MehvarIdentityUser> userManager)
{
if (context.User.Identity.IsAuthenticated)
{
var carNegarUser = await userManager.GetUserAsync(context.User);
context.Items["DealerId"] = carNegarUser.DealerId;
}
await _next(context);
}
}
my problem is that for every request such as requests for static files my middleware's Invoke method is called.
Is there any way to enable the Invoke method to be called just for non-static files requests?
I'm learing about grpc service in java and I'm trying to figure out if it is possible to intercept and modify a request.
I thought of modify the grpc request based on the number specified in the protobuf.
Sample Protobuf:
message PersonRequest {
string name = 1;
int32 id = 2;
bool has_ponycopter = 3;
}
#Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall
(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
// Get by number 1 (name from proto)
// change the name
// send the updated request
}
Is there any approach available to do this.
You can modify the request message in the following server interceptor. Then your serviceImpl will receive the modified request message and process it.
import io.grpc.ForwardingServerCallListener.SimpleForwardingServerCallListener;
...
#Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call, Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
ServerCall.Listener<ReqT> listener = next.startCall(call);
return new SimpleForwardingServerCallListener<ReqT>(listener) {
#Override
public void onMessage(ReqT message) {
ReqT modifiedMessage = modify(message);
delegate().onMessage(modifiedMessage);
}
};
}
I am trying to update an audit entry using the response body advice but as far as I can tell it never gets executed. I see the bean in the logs:
{"timestamp":"2018-08-21T15:48:08.349Z","level":"INFO","thread":"main",
"logger":"org.springframework.data.rest.webmvc.RepositoryRestHandlerAdapter",
"message":"Detected ResponseBodyAdvice bean in responseAuditAdvice","context":"default"}
My controller method looks like this:
#PostMapping(path = "/stage", consumes = {
"application/json"
}, produces = {
"application/json"
})
#ResponseBody
public ResponseEntity<?> stage(#Valid #RequestBody StagingDto stagingDto,
#RequestHeader(HttpHeaders.USER_AGENT) String userAgent,
BindingResult bindingResult) {
I have a RequestAuditAdvice that extends RequestBodyAdviceAdapter and it is working fine. Also if the error flow occurs I see the exception advice executing as well. it is only the response advice that is failing to trigger. Any suggestions?
here is the advice bean:
#Slf4j
#RequiredArgsConstructor(onConstructor_ = #Inject)
#ControllerAdvice
public class ResponseAuditAdvice implements ResponseBodyAdvice<Object> {
private final RequestService requestService;
#Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
#Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) {
log.info("Updating audit for response.");
String ip = new String (request.getRemoteAddress().getAddress().getAddress());
requestService.auditResponse(ip, 200);
return body;
}
}