0Pricing
gRPC & High Performance APIs · 강의

사용자 지정 메타데이터 전송

gRPC 요청과 함께 사용자 지정 키-값 쌍을 메타데이터로 보내고 받는 방법을 알아봅니다.

사용자 지정 메타데이터 전송은(는) CoddyKit의 무료 gRPC & High Performance APIs 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 gRPC & High Performance APIs 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. gRPC & High Performance APIs 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

What is gRPC Metadata?

In gRPC, metadata refers to key-value pairs that are attached to an RPC call, similar to HTTP headers.

Unlike the main message payload, metadata carries information about the call itself, rather than the application data being transmitted.

  • It's for auxiliary data.
  • It travels with requests and responses.
  • It's separate from your protobuf messages.

Why Use Metadata?

Metadata is incredibly useful for carrying information that doesn't belong in your service's primary request or response messages.

Common use cases include:

  • Authentication Tokens: Sending JWTs or API keys.
  • Tracing IDs: Propagating unique request IDs for distributed tracing.
  • Custom Headers: Any other contextual information needed by your services.

Metadata Structure & Types

Metadata consists of a list of key-value pairs.

  • Keys: Are case-insensitive ASCII strings.
  • Values: Can be either ASCII strings or binary data.

For binary values, the key must end with -bin (e.g., auth-token-bin). gRPC handles the encoding for these.

Client: Sending Request Metadata

Clients attach metadata to outgoing requests using the gRPC Metadata class. This object is then added to the gRPC call stub.

You create Metadata.Key objects to define your header keys and their marshallers (how they are converted to/from strings or bytes).

Client: Sending Metadata Example

This Java client snippet shows how to create a Metadata object and attach it to your stub before making an RPC call. Ensure your `hello.proto` is compiled.

package com.coddykit.grpc;

import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.Metadata;
import io.grpc.stub.MetadataUtils;
import io.grpc.StatusRuntimeException;
import java.util.concurrent.TimeUnit;

public class GrpcClient {
  private final ManagedChannel channel;
  private final GreeterGrpc.GreeterBlockingStub blockingStub;

  public GrpcClient(String host, int port) {
    this.channel = ManagedChannelBuilder.forAddress(host, port)
        .usePlaintext()
        .build();
    blockingStub = GreeterGrpc.newBlockingStub(channel);
  }

  public void shutdown() throws InterruptedException {
    channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
  }

  public void sayHello(String name, String customValue) {
    System.out.println("Sending custom-key: " + customValue);
    HelloRequest request = HelloRequest.newBuilder().setName(name).build();

    // 1. Create Metadata object
    Metadata headers = new Metadata();
    // 2. Define a Metadata.Key for your header
    Metadata.Key<String> customKey = Metadata.Key.of(
        "custom-key", Metadata.ASCII_STRING_MARSHALLER);
    // 3. Put the key-value pair into Metadata
    headers.put(customKey, customValue);
    
    // 4. Attach metadata to the stub
    GreeterGrpc.GreeterBlockingStub stubWithMetadata = 
        MetadataUtils.attachHeaders(blockingStub, headers);

    try {
      HelloReply response = stubWithMetadata.SayHello(request);
      System.out.println("Greeting: " + response.getMessage());
    } catch (StatusRuntimeException e) {
      System.err.println("RPC failed: " + e.getStatus());
    }
  }

  public static void main(String[] args) throws Exception {
    GrpcClient client = new GrpcClient("localhost", 50051);
    try {
      client.sayHello("CoddyKit User", "my-session-id-123");
    } finally {
      client.shutdown();
    }
  }
}

Server: Receiving Request Metadata

On the server side, incoming metadata is typically accessed using a ServerInterceptor.

An interceptor sits between the gRPC runtime and your service implementation, allowing you to inspect and modify calls.

  • It receives a Metadata object.
  • You can extract values using Metadata.Key.
  • Often, metadata is then added to the Context for easy access within service methods.

Server: Receiving Metadata Example

This Java server example shows a ServerInterceptor extracting a custom header and making it available to the service via Context. Ensure your `hello.proto` is compiled.

package com.coddykit.grpc;

import io.grpc.Context;
import io.grpc.Metadata;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.ServerCall;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.grpc.stub.StreamObserver;
import java.io.IOException;

public class GrpcServer {
  private Server server;

  // Context.Key to store the custom value for the service method
  private static final Context.Key<String> CUSTOM_VALUE_CTX_KEY = Context.key("custom-value");

  private void start() throws IOException {
    int port = 50051;
    server = ServerBuilder.forPort(port)
        .addService(new GreeterService())
        .intercept(new CustomHeaderInterceptor()) // Add our interceptor
        .build()
        .start();
    System.out.println("Server started, listening on " + port);
    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
      System.err.println("*** shutting down server");
      try { GrpcServer.this.stop(); } 
      catch (InterruptedException e) { e.printStackTrace(System.err); }
      System.err.println("*** server shut down");
    }));
  }

  private void stop() throws InterruptedException {
    if (server != null) { server.shutdown().awaitTermination(); }
  }

  private void blockUntilShutdown() throws InterruptedException {
    if (server != null) { server.awaitTermination(); }
  }

  public static void main(String[] args) throws Exception {
    final GrpcServer server = new GrpcServer();
    server.start();
    server.blockUntilShutdown();
  }

  static class GreeterService extends GreeterGrpc.GreeterImplBase {
    @Override
    public void SayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
      // Retrieve custom value from Context
      String customValue = CUSTOM_VALUE_CTX_KEY.get();
      System.out.println("Service received custom-key: " + customValue);

      HelloReply reply = HelloReply.newBuilder()
          .setMessage("Hello " + request.getName() + 
                      "! Custom value: " + customValue)
          .build();
      responseObserver.onNext(reply);
      responseObserver.onCompleted();
    }
  }

  static class CustomHeaderInterceptor implements ServerInterceptor {
    // Define the Metadata.Key for our custom header
    private static final Metadata.Key<String> CUSTOM_KEY = 
        Metadata.Key.of("custom-key", Metadata.ASCII_STRING_MARSHALLER);

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

      // Get the custom value from incoming headers
      String customValue = headers.get(CUSTOM_KEY);
      System.out.println("Interceptor received custom-key: " + customValue);

      // Store the custom value in the Context for the service to access
      Context context = Context.current().withValue(CUSTOM_VALUE_CTX_KEY, customValue);
      
      // Proceed with the call within the new context
      return Context.current().call(() -> next.startCall(call, headers));
    }
  }
}

Server: Sending Response Metadata

Servers can also send metadata back to clients, either as response headers or response trailers.

  • Response Headers: Sent before any response messages. Use ServerCall.sendHeaders(Metadata).
  • Response Trailers: Sent at the end of the RPC, after all response messages. Often used for status or final context.

Both are handled within the ServerCall object, which is available in interceptors or advanced service implementations.

Client: Receiving Response Metadata

Clients can access the response metadata (headers and trailers) through the ClientCall.Listener interface, typically used with asynchronous (non-blocking) stubs.

The listener provides callbacks like onHeaders(Metadata) and onTrailers(Metadata) where you can inspect the incoming metadata.

Metadata Use Cases

Which of the following is NOT a typical use case for gRPC metadata?

Recap: Metadata in gRPC

You've learned how gRPC metadata acts like HTTP headers, carrying essential non-application data alongside your RPC calls.

  • Clients send metadata with requests.
  • Servers receive and process request metadata (often via interceptors).
  • Servers can send response metadata (headers/trailers) back to clients.
  • Metadata is crucial for cross-cutting concerns like authentication and tracing.

Mastering metadata allows for more robust and observable gRPC services!

자주 묻는 질문

“사용자 지정 메타데이터 전송” 강의는 무료인가요?

네 — “사용자 지정 메타데이터 전송” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 gRPC & High Performance APIs 강의 전체를 잠금 해제할 수 있습니다. gRPC & High Performance APIs 강의에는 총 4개의 강의가 포함되어 있습니다.

“사용자 지정 메타데이터 전송”에서 뭘 배우나요?

gRPC 요청과 함께 사용자 지정 키-값 쌍을 메타데이터로 보내고 받는 방법을 알아봅니다. 브라우저에서 직접 실행하는 실습 코드로 gRPC & High Performance APIs을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

gRPC & High Performance APIs을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 gRPC & High Performance APIs은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“사용자 지정 메타데이터 전송” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 gRPC & High Performance APIs 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 gRPC & High Performance APIs 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 상태 코드 및 오류 처리
  2. 사용자 지정 메타데이터 전송
  3. 컨텍스트 및 기한
  4. google.rpc.Status를 활용한 풍부한 오류 모델
← gRPC & High Performance APIs(으)로 돌아가기