ここ最近業務で API Gateway + Lambda を使った開発を行っており、API Gateway の振る舞いで注意しなければならない点を見つけたので、解決方法も添えて記事にしたいと思います。開発言語は Go言語です
AWS API Gateway がリクエストヘッダーを小文字にしてしまう
- 今回使用するサンプルプログラムです
package main
import (
"errors"
"fmt"
"log"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-lambda-go/lambdacontext"
)
type (
request = events.APIGatewayProxyRequest
response = events.APIGatewayProxyResponse
)
// handler handles AWS Lambda execution.
func handler(ctx context.Context, r request) (response, error) {
if _, ok := lambdacontext.FromContext(ctx); !ok {
return response{StatusCode: http.StatusBadRequest}, errors.New("not invoked from aws lambda")
}
log.Print(r.Headers)
accept, _ := r.Headers["Accept"] // 実際は accept としないと取得できない
if == strings.Contains(accept, "application/json") {
return response{StatusCode: http.StatusOK, Body:"{}"}, nil
}
return response{StatusCode: http.StatusOK, Body: fmt.Sprintf("It Works! path=%s", r.Path)}, nil
}
func main() {
lambda.Start(handler)
}
サンプルプログラムでは Accept ヘッダーが application/json だった場合に空の json を返します。
今回の一例ですが、下記のようなリクエストを送信したとします。
curl -X GET -H "Accept:application/json" https://hogehoge
これが API Gateway を通って Lambda 側にきた時には Accept → accept になっていて、r.Headers["Accept"]
では取得できません。
そもそもRFCの定義では、リクエストヘッダーは小文字大文字を区別しないとなっています。
「とりあえず全部小文字に変換しておくから、アプリケーション側で取得する時は小文字で取得してね」という事なのでしょうかね?
大文字、小文字の区別なく取得できるようにするには
全て小文字で書かなければならないのはとてもモヤモヤします。この問題に対して有効な解決策が、Lambda の SDK 開発の PR の議論のなかにありました。
vents.APIGatewayProxyRequest の header を net/http の header に置き換えてしまうというやり方です。
net/http の Header は CanonicalHeaderKey() を用いて正規化されるので、Accept
でもaccept
でもACCEPT
でも問題ありません。
headers := http.Header{}
for header, values := range r.MultiValueHeaders {
for _, value := range values {
headers.Add(header, value)
}
}
headers.Get("Accept")
golang で Lambda 開発を行う方は是非参考にしてください。