미들웨어로 AWS SDK for Go v2 클라이언트 요청 사용자 지정
주의
클라이언트 요청 파이프라인을 수정하면 형식이 잘못된 또는 유효하지 않은 요청이 발생하거나 예기치 않은 애플리케이션 오류가 발생할 수 있습니다. 이 기능은 SDK 인터페이스에서 기본적으로 제공하지 않는 고급 사용 사례를 위한 것입니다.
서비스 작업의 스택
| 스택 단계 | 설명 |
|---|---|
| 초기화 | 입력을 준비하고 필요에 따라 기본 파라미터를 설정합니다. |
| 직렬화 | 대상 전송 계층에 적합한 프로토콜 형식으로 입력을 직렬화합니다. |
| 빌드 | HTTP Content-Length와 같은 직렬화된 입력에 추가 메타데이터를 연결합니다. |
| 마무리 | 재시도 및 인증을 포함한 최종 메시지 준비입니다(SigV4 서명). |
| 역직렬화 | 프로토콜 형식의 응답을 구조화된 유형 또는 오류로 역직렬화합니다. |
지정된 단계 내의 각 미들웨어에는 미들웨어의 ID 메서드에 따라 결정되는 고유 식별자가 있어야 합니다. 미들웨어 식별자는 특정 미들웨어의 인스턴스 하나만 단계에 등록되도록 하고 다른 단계 미들웨어가 해당 미들웨어에 대해 삽입되도록 허용합니다.
단계의 Insert 또는 Add 메서드를 사용하여 단계 미들웨어를 연결합니다. Add를 사용하여 middleware.BeforeInsert를 사용하여 다른 단계 미들웨어를 기준으로 미들웨어를 삽입하여 미들웨어를 단계에 연결합니다.
주의
Add 메서드를 사용하여 사용자 지정 단계 미들웨어를 안전하게 삽입해야 합니다. Insert를 사용하면 사용자 지정 미들웨어와 삽입하려는 미들웨어 간에 종속성이 생성됩니다. 애플리케이션에 변경 사항이 발생하지 않도록 스택 단계 내의 미들웨어를 불투명한 것으로 간주해야 합니다.
사용자 지정 미들웨어 작성
각 스택 단계에는 지정된 단계에 미들웨어를 연결하기 위해 충족해야 하는 인터페이스가 있습니다. 제공된 함수 중 하나를 사용하여 이 인터페이스를 빠르게 충족할 수 있습니다. 다음 표에는 인터페이스를 충족하는 데 사용할 수 있는 단계, 인터페이스 및 헬퍼 함수가 요약되어 있습니다.StepMiddlewareFunc
다음 예제에서는 제공되지 않은 경우 사용자 지정 미들웨어를 작성하여 Amazon S3 GetObject API 직접 호출의 버킷 멤버를 채우는 방법을 보여줍니다. 이 미들웨어는 다음 예제에서 참조되어 스택에 단계 미들웨어를 연결하는 방법을 보여줍니다.
import "github.com/aws/smithy-go/aws" import "github.com/aws/smithy-go/middleware" import "github.com/aws/aws-sdk-go-v2/service/s3" // ... var defaultBucket = middleware.InitializeMiddlewareFunc("DefaultBucket", func( ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, ) ( out middleware.InitializeOutput, metadata middleware.Metadata, err error, ) { // Type switch to check if the input is s3.GetObjectInput, if so and the bucket is not set, populate it with // our default. switch v := in.Parameters.(type) { case *s3.GetObjectInput: if v.Bucket == nil { v.Bucket = aws.String("amzn-s3-demo-bucket") } } // Middleware must call the next middleware to be executed in order to continue execution of the stack. // If an error occurs, you can return to prevent further execution. return next.HandleInitialize(ctx, in) })
모든 클라이언트에 미들웨어 연결
aws.ConfigAPIOptions 멤버를 사용해 미들웨어를 추가하여 사용자 지정 단계 미들웨어를 모든 클라이언트에 연결할 수 있습니다. 다음 예제에서는 애플리케이션 aws.Config 객체를 사용하여 구성된 모든 클라이언트에 defaultBucket 미들웨어를 연결합니다.
import "context" import "github.com/aws/aws-sdk-go-v2/aws" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" import "github.com/aws/smithy-go/middleware" // ... cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { // handle error } cfg.APIOptions = append(cfg.APIOptions, func(stack *middleware.Stack) error { // Attach the custom middleware to the beginning of the Initialize step return stack.Initialize.Add(defaultBucket, middleware.Before) }) client := s3.NewFromConfig(cfg)
특정 작업에 미들웨어 연결
작업에 대한 가변 인수 목록을 사용하여 클라이언트의 APIOptions 멤버를 수정하는 방법으로 사용자 정의 단계 미들웨어를 특정 클라이언트 작업에 첨부할 수 있습니다. 다음 예제에서는 defaultBucket 미들웨어를 특정 Amazon S3 GetObject 작업 간접 호출에 연결합니다.
import "context" import "github.com/aws/aws-sdk-go-v2/aws" import "github.com/aws/aws-sdk-go-v2/config" import "github.com/aws/aws-sdk-go-v2/service/s3" import "github.com/aws/smithy-go/middleware" // ... // registerDefaultBucketMiddleware registers the defaultBucket middleware with the provided stack. func registerDefaultBucketMiddleware(stack *middleware.Stack) error { // Attach the custom middleware to the beginning of the Initialize step return stack.Initialize.Add(defaultBucket, middleware.Before) } // ... cfg, err := config.LoadDefaultConfig(context.TODO()) if err != nil { // handle error } client := s3.NewFromConfig(cfg) object, err := client.GetObject(context.TODO(), &s3.GetObjectInput{ Key: aws.String("my-key"), }, func(options *s3.Options) { // Register the defaultBucketMiddleware for this operation only options.APIOptions = append(options.APIOptions, registerDefaultBucketMiddleware) })
스택으로 메타데이터 전달
특정 상황에서는 정보 또는 상태를 공유하여 둘 이상의 미들웨어가 동시에 작동해야 할 수 있습니다. context.Contextmiddleware.WithStackValue는 지정된 키-값 페어를 제공된 컨텍스트에 연결하고 범위를 현재 실행 중인 스택으로 안전하게 제한합니다. 이러한 스택 범위 값은 middleware.GetStackValuecontext.Context를 사용하여 스택에 정보를 전달하는 방법을 보여줍니다.
import "context" import "github.com/aws/smithy-go/middleware" // ... type customKey struct {} func GetCustomKey(ctx context.Context) (v string) { v, _ = middleware.GetStackValue(ctx, customKey{}).(string) return v } func SetCustomKey(ctx context.Context, value string) context.Context { return middleware.WithStackValue(ctx, customKey{}, value) } // ... var customInitalize = middleware.InitializeMiddlewareFunc("customInitialize", func( ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, ) ( out middleware.InitializeOutput, metadata middleware.Metadata, err error, ) { ctx = SetCustomKey(ctx, "my-custom-value") return next.HandleInitialize(ctx, in) }) var customBuild = middleware.BuildMiddlewareFunc("customBuild", func( ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler, ) ( out middleware.BuildOutput, metadata middleware.Metadata, err error, ) { customValue := GetCustomKey(ctx) // use customValue return next.HandleBuild(ctx, in) })
SDK에서 제공하는 메타데이터
AWS SDK for Go는 제공된 컨텍스트에서 검색할 수 있는 여러 메타데이터 값을 제공합니다. 이러한 값을 사용하여 실행 중인 서비스, 작업 또는 대상 리전에 따라 동작을 수정하는 보다 동적인 미들웨어를 활성화할 수 있습니다. 사용 가능한 몇 가지 키가 아래 표에 나와 있습니다.
| 키 | 리트리버 | 설명 |
|---|---|---|
| ServiceID | GetServiceID |
실행 중인 스택의 서비스 식별자를 검색합니다. 이를 서비스 클라이언트 패키지의 ServiceID 상수와 비교할 수 있습니다. |
| OperationName | GetOperationName |
실행 중인 스택의 작업 이름을 검색합니다. |
| Logger | GetLogger |
미들웨어에서 메시지를 로깅하는 데 사용할 수 있는 로거를 검색합니다. |
스택에 메타데이터 전달
미들웨어 메타데이터ResultMetadata 구조 멤버를 통해 작업의 출력 셰이프를 따라 간접 호출 애플리케이션에 액세스할 수 있습니다.
다음 예제에서는 사용자 지정 미들웨어가 작업 출력의 일부로 반환되는 메타데이터를 추가하는 방법을 보여줍니다.
import "context" import "github.com/aws/aws-sdk-go-v2/service/s3" import "github.com/aws/smithy-go/middleware" // ... type customKey struct{} func GetCustomKey(metadata middleware.Metadata) (v string) { v, _ = metadata.Get(customKey{}).(string) return v } func SetCustomKey(metadata *middleware.Metadata, value string) { metadata.Set(customKey{}, value) } // ... var customInitalize = middleware.InitializeMiddlewareFunc("customInitialize", func ( ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler, ) ( out middleware.InitializeOutput, metadata middleware.Metadata, err error, ) { out, metadata, err = next.HandleInitialize(ctx, in) if err != nil { return out, metadata, err } SetCustomKey(&metadata, "my-custom-value") return out, metadata, nil }) // ... client := s3.NewFromConfig(cfg, func (options *s3.Options) { options.APIOptions = append(options.APIOptions, func(stack *middleware.Stack) error { return stack.Initialize.Add(customInitalize, middleware.After) }) }) out, err := client.GetObject(context.TODO(), &s3.GetObjectInput{ // input parameters }) if err != nil { // handle error } customValue := GetCustomKey(out.ResponseMetadata)