テストデバイスのAPIをCDN経由で動作するように切り替えました。iOSが動作し、Androidも動作しているようですが、しばらくお待ちください。 Androidアプリケーションでは、GETおよびHEADリクエストのみが機能し、POST、PUTなどは502に該当します。iOSおよびAndroidアプリケーションのトラフィックの簡単な調査と比較の後、Androidはリクエストで「Transfer-Encoding:chunked」ヘッダーを送信します。
カールを使用してAPIページをプルしようとします。
curl https://cdn.api.example.com -XPOST -d 'test=data'
動作します。 そして、あなたがこのようにしようとしたら:
curl https://cdn.api.example.com -XPOST -d 'test=data' -H 'Transfer-Encoding: chunked'
ええ、CDNを使用しなくてもこのようなクエリは問題なく機能しますが、機能しません。
nginxのアクセスログでは、リクエストが400 Badリクエストコードで失敗したことがわかります。
ただし、curlは「Transfer-Encoding:chunked」ヘッダーを送信するが、データを適切に生成しないという問題がある可能性があります。 チャンクでデータを送信する小さなPythonスクリプトを作成して、このオプションを確認しましょう。
import requests import logging import httplib as http_client http_client.HTTPConnection.debuglevel = 1 logging.basicConfig() logging.getLogger().setLevel(logging.DEBUG) requests_log = logging.getLogger("requests.packages.urllib3") requests_log.setLevel(logging.DEBUG) requests_log.propagate = True def test(): yield 'data' yield 'test' s = requests.Session() data = s.post('https://cdn.api.example.com', data=test())
スクリプトは30秒間ハングし(30秒はCDN設定の書き込み要求タイムアウトです)、エラーで失敗します。
出力には以下が表示されます。
send: 'POST cdn.api.example.com HTTP/1.1\r\nHost: cdn.api.example.com\r\nConnection: keep-alive\r\nAccept-Encoding: gzip, deflate\r\nAccept: */*\r\nUser-Agent: python-requests/2.18.4\r\nTransfer-Encoding: chunked\r\n\r\n' send: '4' send: '\r\n' send: 'data' send: '\r\n' send: '4' send: '\r\n' send: 'test' send: '\r\n' send: '0\r\n\r\n' reply: 'HTTP/1.1 502 Bad Gateway\r\n' header: Date: Mon, 11 Dec 2017 22:05:04 GMT header: Connection: Keep-Alive header: Accept-Ranges: bytes header: Cache-Control: max-age=10 header: Content-Length: 0 header: X-HW: 1
要求が正しいことがわかります。最後のチャンクの後に、長さがゼロのメッセージ「0 \ r \ n \ r \ n」があり、すべてのチャンクが送信されたことをWebサーバーに伝えています。 ただし、CDNサーバーはさらに多くのチャンクを待機し続け、30秒後にタイムアウトにより低下します。
しかし、CDNのすべての非難を非難するには時期尚早です。 思い出すと、リクエストはnginxに届きますが、コード400で落ちます。nginxが原因である可能性はありますか? これを確認するには、トラフィックをダンプし、Wiresharkの[Follow TCP Stream]オプションを選択して、読み取り可能な形式のデータを表示します。
POST / HTTP/1.1 Date: Tue, 12 Dec 2017 07:19:48 GMT Host: cdn.api.example.com Connection: Keep-Alive Accept-Encoding: gzip, deflate Accept: */* User-Agent: python-requests/2.18.4 Transfer-Encoding: chunked
ご覧のように、nginxはヘッダーを受信しましたが、POSTデータはヘッダーに到達しませんでした。CDNサーバーがクライアント502を提供してnginxから切断すると、無効な要求を受信したことを示すメッセージをログに書き込む以外に何も残っていません。
最後の可能性を考えてみましょう。CDNは「Transfer-Encoding:chunked」で動作する必要はないかもしれません。アプリケーションで使用したのは私たちのせいですか? RFC 7230がそれについて考えていることを読みます 。 私たちが探しているのは、セクション3.3.1および4.1で見つかりました。 標準では、要求と応答の両方で「Transfer-Encoding:chunked」の使用が許可されています。 これは、これがHTTP / 1.1の必須部分であり、この標準を実装するすべてのアプリケーションでサポートされる必要があることを個別に示しています。
問題がCDN側のHTTPサーバーの誤動作であるというすべての証拠を収集しました。 サポートのチケットを作成し、問題の詳細をすべて明確にし、エンジニアとコミュニケーションをとった後、すばらしい回答を得ました。
これはシステムのバグではなく、リクエスト内のチャンクエンコーディングが設計上機能していないことを確認しています。この後、追加することすらありません。 また、HighwindsがVarnishやNginxなどのHTTPサーバーのオープンソース実装を使用し、「設計上」そのような機能を独自に作成しなかった場合、問題は発生しなかったことにも注意してください。 HTTPプロトコルの偽物に注意してください。