Я перемещаю кодовую базу распределенных систем из SOAP (JAX-WS) в gRPC-java.
Мы используем эту кодовую базу для обучения удаленным вызовам, отказоустойчивости, реализации безопасности.
В архитектуре JAX-WS существует класс-перехватчик (называемый обработчиком SOAP), который может перехватывать сообщения SOAP. Вы можете настроить обработчики на клиенте и на сервере.
Для справки, это полная последовательность для удаленного вызова на JAX-WS:
- Клиент - создать порт (заглушку) и вызвать удаленный метод
- Stub - конвертировать объекты Java в сообщение SOAP (XML)
- ClientHandler - перехватывает исходящее SOAP-сообщение и может читать / записывать его
- Сеть - передано сообщение запроса SOAP
- ServerHandler - перехватывает входящее SOAP-сообщение, может читать / писать
- Tie - преобразовать SOAP-сообщение в объекты Java
- Сервер - выполнить метод, ответить
- ServerHandler - перехватывает исходящий SOAP-ответ, может читать / писать
- Сеть - передано ответное сообщение SOAP
- Клиент - создать порт (заглушку) и вызвать удаленный метод
- Stub - преобразовать объекты Java в сообщение SOAP (XML)
- ClientHandler - перехватывает входящее SOAP-сообщение
- Клиент - получает ответ
При таком подходе мы можем создавать обработчики для регистрации сообщений SOAP и для обеспечения безопасности, такой как цифровая подпись или шифрование.
Я пытаюсь использовать аналогичные возможности с gRPC на Java (v1.17.2).
Я основал свой код gRPC в этом уроке google , простом привет мире с унарным методом.
На основании этих примеров я написал ClientInterceptor :
package example.grpc.client;
import java.util.Set;
import io.grpc.*;
public class HelloClientInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor,
CallOptions callOptions, Channel channel) {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
channel.newCall(methodDescriptor, callOptions)) {
@Override
public void sendMessage(ReqT message) {
System.out.printf("Sending method '%s' message '%s'%n", methodDescriptor.getFullMethodName(),
message.toString());
super.sendMessage(message);
}
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
System.out.println(HelloClientInterceptor.class.getSimpleName());
ClientCall.Listener<RespT> listener = new ForwardingClientCallListener<RespT>() {
@Override
protected Listener<RespT> delegate() {
return responseListener;
}
@Override
public void onMessage(RespT message) {
System.out.printf("Received message '%s'%n", message.toString());
super.onMessage(message);
}
};
super.start(listener, headers);
}
};
}
}
Я создал ServerInterceptor :
package example.grpc.server;
import java.util.Set;
import io.grpc.*;
public class HelloServerInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall, Metadata metadata,
ServerCallHandler<ReqT, RespT> serverCallHandler) {
// print class name
System.out.println(HelloServerInterceptor.class.getSimpleName());
return Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler);
}
}
Вот (наконец) мои вопросы:
- Как сервер-перехватчик может увидеть сообщение до и после выполнения метода?
- Как сервер-перехватчик может изменить сообщение?
- Как клиент-перехватчик может изменить сообщение?
Конечная цель состоит в том, чтобы иметь возможность написать CipherClientHandler и CipherServerHandler, которые бы шифровали байты сообщения по проводам. Я знаю, что TLS - верный способ сделать это на практике, но я хочу, чтобы студенты делали индивидуальную реализацию.
Спасибо за любые указатели в правильном направлении!