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);
}
};
}
Related
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?
IApplicationBuilder has a .Map method that all the examples online show you how to use when you are inlining your middleware configuration and using .Run or .Use directly.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/?view=aspnetcore-2.2#use-run-and-map
Most of the examples then go on to say how this is a bad idea (rightly so for maintenance reasons alone) and show you how to make a middle ware component which looks something like this:
public class CustomMiddleware: IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
... do stuff.
await next(context);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CustomMiddleware>();
}
}
What I can't see is how to combine the two. One thing I tried was this:
public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder builder)
{
return builder.Map("/CustomPath", app => {
app.UseMiddleware<CustomMiddleware>(); });
}
}
But this is apparently not working as it is calling InvokeAsync for everything.
I could easily look at the HttpContext.Request.Path and skip my do stuff if it does not match but wanted to know if it was possible to use .Map before doing so.
The code you provided in working as it should and yielding the result you desire; InvokeAsync is called only when the current request path starts with the one provided to Map -I'm not sure if this small detail is what might be causing the issue i.e. /CustomPath/anything will match and cause Map to invoke the different pipeline-.
For example using the following code in a new template:
Map will match /home, /home/privacy, /home/values etc.
Map won't match /anything_not_starting_with_home, and InvokeAsync won't be called.
public static class CustomMiddlewareExtensions {
public static IApplicationBuilder UseCustomMiddleware(this IApplicationBuilder appBuilder) {
appBuilder.Map("/home", b => {
b.UseMiddleware<CustomMiddleware1>();
b.UseMiddleware<CustomMiddleware2>();
});
return appBuilder;
}
public class CustomMiddleware1 {
private readonly RequestDelegate _next;
public CustomMiddleware1(RequestDelegate next) {
_next = next;
}
public async Task InvokeAsync(HttpContext context) {
Debug.WriteLine($" ======== Response handled by {nameof(CustomMiddleware1)} ======== ");
await _next.Invoke(context);
}
}
public class CustomMiddleware2 {
private readonly RequestDelegate _next;
public CustomMiddleware2(RequestDelegate next) {
_next = next;
}
public async Task InvokeAsync(HttpContext context) {
Debug.WriteLine($" ======== Response handled by {nameof(CustomMiddleware2)} ======== ");
await context.Response.WriteAsync("Custom Middleware used");
}
}
}
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);
}
};
}
}
I want to log the json data which is posted from the client. I have written the interceptor also. I am receiving request but I am unable to log the json part of the reuqest. How can I do it?
here is my postdata json:
{"callerId":3456,"sessionId":"1554ba7c-b729-4dc5-9dd2-c48e2b275c3f","uniqueId":"some","courseProgress":{"bookmark":{"contentId":"aec4b2c5-6766-4d51-80ac-8fdc61f465ed","version":1}}}
here is my loggerInterceptor code :
public class LoggerInterceptor extends HandlerInterceptorAdapter {
static Logger logger = Logger.getLogger(LoggerInterceptor.class);
static {
BasicConfigurator.configure();
}
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
logger.info("Before handling the request");
return super.preHandle(request, response, handler);
}
}
So I am getting the request but not able to retreive the json data