본문 바로가기
개발/gRPC

[gRPC/java] Header에 Custom Variable을 전달하고 사용하는 방법 (gRPC ServerInterceptor)

by 돌돌블로거 2024. 12. 17.


gRPC에서는 클라이언트가 서버로 요청을 보낼 때 Header에 메타데이터를 추가 할 수 있다. 
이 때, Interceptor를 사용하면 서버의 서비스 메서드에서 커스텀 헤더 값을 읽고 사용할 수 있다.

이 포스팅에서는 ServerInterceptor를 이용해 클라이언트가 보낸 헤더의 값을 서버에서 Context를 통해 서비스 메서드로 전달하는 방법을 설명해보고자 한다.

1. gRPC Context Key 정의
Context를 통해 값을 저장하고 읽기 위해 Context.Key를 정의.

import io.grpc.Context;

public class ContextKeys {
    // Context에 저장할 Key 정의
    public static final Context.Key<String> VAR_KEY = Context.key("var");
}

 

2. ServerInterceptor 구현
Interceptor를 이용해 클라이언트의 Header에서 var 값을 읽고, 이를 gRPC Context에 저장.

import io.grpc.*;

public class VarInterceptor implements ServerInterceptor {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
            ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {

        // 헤더에서 var 값을 읽음
        Metadata.Key<String> varKey = Metadata.Key.of("var", Metadata.ASCII_STRING_MARSHALLER);
        String var = headers.get(varKey);

        // var 값이 없는 경우 기본값 설정
        if (var == null) {
            var = "default-var";
        }

        System.out.println("Var value from header: " + var);

        // Context에 var 값을 저장
        Context contextWithVar = Context.current().withValue(ContextKeys.VAR_KEY, var);

        // Context를 적용하여 다음 단계로 전달
        return Contexts.interceptCall(contextWithVar, call, headers, next);
    }
}

 

3. 서비스 메서드에서 Context 값 읽기
gRPC 서비스 메서드에서는 Context를 통해 Interceptor에서 저장한 값을 가져와 사용할 수 있음.

import io.grpc.stub.StreamObserver;

public class MyService extends MyServiceGrpc.MyServiceImplBase {

    @Override
    public StreamObserver<MyRequest> myStreamingMethod(StreamObserver<MyResponse> responseObserver) {
        // Context에서 var 값 읽기
        String var = ContextKeys.VAR_KEY.get();
        System.out.println("Var value in service method: " + var);

        return new StreamObserver<MyRequest>() {
            @Override
            public void onNext(MyRequest request) {
                System.out.println("Processing request for var: " + var);
                // 클라이언트 요청 처리 로직
            }

            @Override
            public void onError(Throwable t) {
                System.err.println("Error occurred for var: " + var);
            }

            @Override
            public void onCompleted() {
                System.out.println("Stream completed for var: " + var);
                responseObserver.onCompleted();
            }
        };
    }
}

 

4. Interceptor를 gRPC 서버에 등록
gRPC 서버를 설정할 때 VarInterceptor를 추가.

import io.grpc.Server;
import io.grpc.ServerBuilder;

public class GrpcServer {
    public static void main(String[] args) throws Exception {
        Server server = ServerBuilder.forPort(8000)
                .addService(new MyService())       // gRPC 서비스
                .intercept(new VarInterceptor()) // Interceptor 추가
                .build();

        System.out.println("gRPC Server started on port 8000");
        server.start();
        server.awaitTermination();
    }
}



작동 원리

1. 클라이언트는 요청을 보낼 때 Header에 var 값을 설정.
2. Interceptor:
요청을 가로채고, Header에서 var 값을 읽어 Context에 저장.
3. 서비스 메서드:
Context를 통해 저장된 var 값을 가져와 사용할 수 있음.

예제 실행 출력

1. 클라이언트가 var=prod를 포함한 요청을 보낸 경우:

Var value from header: prod
Var value in service method: prod
Processing request for var: prod
Stream completed for var: prod

2. 클라이언트가 var 값을 보내지 않은 경우:

Var value from header: default-var
Var value in service method: default-var
Processing request for var: default-var
Stream completed for var: default-var

 

결론

ServerInterceptorContext를 활용하면 gRPC Header의 Custom Variable을 서비스 메서드까지 안전하게 전달하고 사용할 수 있다. 이를 통해 서버는 요청에 대한 특정 식별자(예: var, client-id)를 기반으로 로직을 실행할 수 있다.

이 구현 방식은 확장성과 재사용성이 뛰어나며, 인증, 로깅, 클라이언트 구분 등 다양한 상황에서 활용할 수 있다.

반응형

'개발 > gRPC' 카테고리의 다른 글

[gRPC] gRPC란?  (2) 2024.11.13