티스토리 뷰
* 개인적으로 공부한 내용의 일부를 기록하기 위한 것이므로 중간 과정이 많이 생략되어 있습니다. *
작성중인 코드의 일부는 아래의 깃허브 저장소에서 확인하실 수 있습니다.
https://github.com/piatoss3612/go-grpc-todo
1. 메타데이터 읽기
메타데이터에 어떤 정보가 담겨있는지 먼저 확인해 봅니다.
package server
import (
"context"
"fmt"
"golang.org/x/exp/slog"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata" // 메타데이터를 읽어오기 위해 사용하는 패키지
)
func TodoServerUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
md, ok := metadata.FromIncomingContext(ctx) // 요청 context로부터 메타데이터 읽기
// 메타데이터가 존재하는 경우
if ok {
// 메타데이터 출력
for k, v := range md {
fmt.Println(k, v)
}
}
...
}
2. 메타데이터 추출 및 출력
어떤 정보들이 담겨있는지 확인했으니, 사용자 에이전트와 클라이언트 ip 정보만 가져와 보겠습니다.
func TodoServerUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
var userAgent, clientIp string
if md, ok := metadata.FromIncomingContext(ctx); ok {
// 사용자 에이전트 정보가 있는 경우에만
if userAgents := md.Get("user-agent"); len(userAgents) > 0 {
userAgent = userAgents[0]
}
// 게이트웨이 사용자 에이전트 정보가 있는 경우에는 사용자 에이전트 정보에 덮어쓴다
if gwUserAgents := md.Get("grpcgateway-user-agent"); len(gwUserAgents) > 0 {
userAgent = gwUserAgents[0]
}
// 클라이언트 ip 정보가 있는 경우에만
if clientIps := md.Get("x-forwarded-for"); len(clientIps) > 0 {
clientIp = clientIps[0]
}
}
slog.Info("Request received", "method", info.FullMethod, "user-agent", userAgent, "client-ip", clientIp)
...
}
gRPC 클라이언트에서 직접 요청을 할 경우에는 메타데이터에 클라이언트의 ip주소가 포함되어 있지 않는데, 어디서 클라이언트의 ip주소를 가져와야 될까요?
3. gRPC 클라이언트의 IP 가져오기
package server
import (
"context"
"fmt"
"golang.org/x/exp/slog"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
)
func TodoServerUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
var userAgent, clientIp string
if md, ok := metadata.FromIncomingContext(ctx); ok {
if userAgents := md.Get("user-agent"); len(userAgents) > 0 {
userAgent = userAgents[0]
}
// 클라이언트 정보 추출
peer, ok := peer.FromContext(ctx)
if ok {
clientIp = peer.Addr.String()
}
if gwUserAgents := md.Get("grpcgateway-user-agent"); len(gwUserAgents) > 0 {
userAgent = gwUserAgents[0]
}
if clientIps := md.Get("x-forwarded-for"); len(clientIps) > 0 {
clientIp = clientIps[0]
}
}
slog.Info("Request received", "method", info.FullMethod, "user-agent", userAgent, "client-ip", clientIp)
resp, err := handler(ctx, req)
if err != nil {
slog.Error("Request failed", "method", info.FullMethod, "error", err)
return resp, err
}
slog.Info("Send a message", "type", fmt.Sprintf("%T", resp))
return resp, nil
}
peer 패키지의 FromContext 함수를 사용해서 gRPC 요청 컨텍스트로부터 클라이언트의 ip 정보를 추출해낼 수 있습니다.
4. 메타데이터 추출 함수 정의
메타데이터를 추출하는 과정이 상당히 기므로 별개의 타입과 함수로 정의해 보았습니다.
package server
import (
"context"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/peer"
)
type todoServerMetadata struct {
userAgent string
clientIp string
}
func extractMetadata(ctx context.Context) todoServerMetadata {
var userAgent, clientIp string
if md, ok := metadata.FromIncomingContext(ctx); ok {
if userAgents := md.Get("user-agent"); len(userAgents) > 0 {
userAgent = userAgents[0]
}
peer, ok := peer.FromContext(ctx)
if ok {
clientIp = peer.Addr.String()
}
if gwUserAgents := md.Get("grpcgateway-user-agent"); len(gwUserAgents) > 0 {
userAgent = gwUserAgents[0]
}
if clientIps := md.Get("x-forwarded-for"); len(clientIps) > 0 {
clientIp = clientIps[0]
}
}
return todoServerMetadata{userAgent: userAgent, clientIp: clientIp}
}
Reference
'개발 부스러기' 카테고리의 다른 글
WSL에서 Go 사용하기 (0) | 2023.12.26 |
---|---|
Chainlink - Data Feeds (0) | 2023.10.31 |
바빌로니아 법 (The Babylonian Method) (0) | 2023.04.10 |
[Nginx] Reverse Proxy 설정 (0) | 2023.04.03 |
[Trouble Shooting] net::ERR_NAME_NOT_RESOLVED (0) | 2023.04.02 |