結論
2016/11/17 API GatewayでBinaryデータの送受信がサポートされましたので、このエントリーは無効となりました。よかったね!
Amazon API Gatewayは Content-Type: application/octet-stream なデータをPOSTで受信しても、無意味なデータができあがってしまいます
この件、ドキュメントには書いてないようです。。。
※gzipなデータを送りたければ Content-Encoding: gzip ヘッダをつければ大丈夫です
概要
Forumにも書かれているとおり、Amazon API GatewayはPOSTされたpayloadに対してUTF-8変換を行うようです
この時non-ASCIIなbyteは 0xEF 0xBF 0xBD に変換されてしまうため、POST元のpayloadデータと一致しない、改変されたデータが作られることになります
そしてIntegrated Requestにおいては $input.body
は、改変後データが格納されており、オリジナルを取得する方法が見つかりません
検証方法
- Amazon API Gatewayで受けたPOSTをS3(bucket: apigw-testing)に保存するようにセットアップ
- 下記 target.json をそれぞれの形式で圧縮
- curlを使って検証
Amazon API Gatewayのセットアップ
基本的にはチュートリアルに沿って作ります
下記はオリジナルです(設定方法は割愛で)
-
POST https://APIGATEWAY/STAGE/{type}
でS3に保存されるオブジェクト名をコントロールできるようにしています
あと、セットアップ中のテストではAPI GatewayのHTTP ProxyでTestでのみエラーが発生するといった罠が現在あるようですので、バケットを作るリージョンはお気をつけて
検証
$ convert -size 1x1 xc:#990000 original.gif
$ curl -H "Content-Type: application/octet-stream" --data-binary @original.gif -X POST https://${APIGATEWAY}.execute-api.ap-northeast-1.amazonaws.com/prod/apigw.gif
$ aws s3api get-object --bucket apigw-testing --key apigw.gif apigw.gif
{
"AcceptRanges": "bytes",
"ContentType": "application/octet-stream",
"LastModified": "Fri, 27 May 2016 00:53:14 GMT",
"ContentLength": 53,
"ETag": "\"7276f51bcbfb892c6ba28a54af1842fc\"",
"Metadata": {}
}
確認
$ wc -c original.gif apigw.gif
43 original.gif
53 apigw.gif
$ od -tx1z original.gif
0000000 47 49 46 38 39 61 01 00 01 00 f0 01 00 00 00 00 >GIF89a..........<
0000020 ff ff ff 21 f9 04 00 00 00 00 00 2c 00 00 00 00 >...!.......,....<
0000040 01 00 01 00 00 02 02 44 01 00 3b >.......D..;<
0000053
$ od -tx1z apigw.gif
0000000 47 49 46 38 39 61 01 00 01 00 ef bf bd 01 00 00 >GIF89a..........<
0000020 00 00 ef bf bd ef bf bd ef bf bd 21 ef bf bd 04 >...........!....<
0000040 00 00 00 00 00 2c 00 00 00 00 01 00 01 00 00 02 >.....,..........<
0000060 02 44 01 00 3b >.D..;<
0000065
0xF0 や 0xFF が 0xEF 0xBF 0xBD に変換されている(そのためサイズも変更されてる)
どうしてもバイナリを送りたい
現時点では、直接Amazon API Gatewayでバイナリを取り扱うことはできませんでしたが、送信側でBase64 encodingができるなら、まだ道はあります
Integration Requestで $util.base64Decode()
を使えば、受け取ったBase64edな文字列をdecodeしたあとのバイナリデータで後続のサービスに引き渡すことができます
あとがき
ま、RESTな環境でnon-ASCIIなデータを送るってのもレアケースですよね