You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言中如何在Unary RPC处理函数内设置响应头(含缓存控制)

Setting Response Headers (Including Cache Control) in Go gRPC Unary Handlers

Got it, I've run into this exact issue before when trying to set cache headers in unary gRPC handlers. The key insight here is that even though unary RPC method signatures don't include a grpc.ServerStream (unlike streaming RPCs), you can still manipulate response headers using gRPC's context-based helper functions.

How It Works

gRPC embeds all necessary RPC context into the context.Context passed to your unary handler. You can use two core functions from the google.golang.org/grpc package to manage headers:

  • grpc.SendHeader(ctx, metadata): Sends initial response headers to the client (must be called before returning the response message).
  • grpc.SetTrailer(ctx, metadata): Sets trailing metadata (can be called before or after sending the response).

Step-by-Step Example

First, make sure you import the required packages:

import (
    "context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/metadata"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/status"
)

Then, in your unary handler, create and send the cache control headers:

func (s *yourServer) GetProduct(ctx context.Context, req *GetProductRequest) (*GetProductResponse, error) {
    // 1. Build your cache control (and other) headers as gRPC metadata
    responseHeaders := metadata.Pairs(
        "cache-control", "public, max-age=3600", // Standard cache control header
        "x-custom-cache-tag", "product-data",    // Optional custom header
    )

    // 2. Send the headers to the client
    if err := grpc.SendHeader(ctx, responseHeaders); err != nil {
        return nil, status.Errorf(
            codes.Internal,
            "failed to send response headers: %v",
            err,
        )
    }

    // 3. Proceed with your normal request logic
    product, err := s.fetchProductFromDB(req.ProductID)
    if err != nil {
        return nil, status.Errorf(codes.NotFound, "product not found: %v", err)
    }

    // Optional: Set trailing metadata if needed (e.g., cache status)
    trailingMetadata := metadata.Pairs("x-cache-status", "hit")
    grpc.SetTrailer(ctx, trailingMetadata)

    return &GetProductResponse{Product: product}, nil
}

Key Notes

  • Timing Matters: grpc.SendHeader must be called before you return the response message. Once the response is sent, you can't modify the initial headers.
  • Header Naming: gRPC follows HTTP/2 conventions, so header keys are typically lowercase. While gRPC will normalize mixed-case keys, using lowercase avoids unexpected behavior.
  • Client Side: If you're using a gRPC client, you can capture these headers using grpc.Header() when making the call:
    var header metadata.MD
    resp, err := client.GetProduct(
        ctx,
        &GetProductRequest{ProductID: 123},
        grpc.Header(&header),
    )
    // Access headers via header.Get("cache-control")
    
  • gRPC-Gateway: If you're using gRPC-Gateway to expose your RPC as HTTP endpoints, these headers will automatically be passed through to the HTTP response, making your cache control rules work for HTTP clients too.

内容的提问来源于stack exchange,提问作者thurt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:59:48