fbpx

メニュー

Nginxでの400 Bad RequestはCookieが原因かも

高橋文樹 高橋文樹

この投稿は 9年半 前に公開されました。いまではもう無効になった内容を含んでいるかもしれないことをご了承ください。

昨日ブログを書いたのですが、その登場人物S氏から「俺の携帯だとブログ見られない」という連絡を頂きました。どうも400 Bad Requestが出ていたようです。

状況をまとめると……

  • 去年までは見られていた
  • 端末は DocomoのMEDIAS ES N-05D
  • OSはAndroidの2.3系(バージョンアップはしていない様子)
  • FacebookやTwitterでソーシャルデバッギングをしかけたところ、他のAndroid2.3のユーザーは見られているとのこと

 

というわけで調べてみました。S氏には「とりあえずドコモショップに言ってOSとファームウェアをアップデートしてもらって」と伝えたのですが、ドコモ店員に向かって「このサイトが見られない」というクレームを入れたようで、なんか僕のところに電話かかってきました……。

家族を人質にでも取られない限り、ドコモショップの店員はやるまいと思いましたね。

400 Bad Requestとは

直訳すると「悪い要求」なのでクライアント(見る側)の問題ではあるようです。ググると「クッキー消せ」という情報が出てきますね。

まあ、「クッキー消して」と頼んでなんとかなる規模ならばいいのですが、沢山のユーザーを抱えるサイトで同じことが起きたらやだなと思ったので、ちょっと調べてみました。

で、色々ググったところ、 Dealing with Nginx 400 Bad Request HTTP errors というブログ記事を発見。ここによると、400 Bad requestはCookieが大き過ぎるとなるよと書いてありました。

で、最後にはNginxのドキュメントに行き当たりました。large_client_header_buffersの項目にこんなことが書いてあります。

このディレクティブはクライアントからのリクエストに含まれる大きなヘッダーを読みとるためのバッファーの数およびサイズを割り当てます。

リクエストの行は1つのバッファーのサイズより小さくないといけません。もしクライアントがそれよりも大きいヘッダーを送信した場合、nginxは ”Request URI too large(414)” を返します。

また、ヘッダーの一番長い行も1つのバッファーのサイズを超えてはいけません。超えた場合、クライアントは ”Bad request(400)”を受け取ります。

バッファーは必要に応じて分割されます。

初期値では1つのバッファーのサイズは8192バイトです。古いnginxではこの値は1ページあたりの容量と同じで、プラットフォームによって4kまたは8kとなり、動作中のリクエスト接続がkeep-aliveに移行するとバッファーは解放されます。

HttpCoreModule – Nginx Community

最後の文はちょっと翻訳怪しいですが、要するにここに設定された値を超えたヘッダーを受け取るとエラーになるよということですね。

CookieはHTTP Request Headerであり、RFCによれば(参考: Internet Explorer の cookie の数とサイズの制限)1行が4kb程度なはずなのですが、ブラウザによってはこれを超えるクッキーを許容するようです。

となると、少なくともCookieを含められる値を large_client_header_buffers に設定すれば動くんじゃないかということになりますね。したがって、これを次のように設定します。

http{
    # httpディレクティブに書きます
    large_client_header_buffers 4 256k;
}

S氏に確認しながらやった結果、最終的に256kまで増加しないと見られるようになりませんでした。そんなにCookieに保存することあるの……

結局のところ、なにによってCookieが増加しているのかはわからなかったのですが、Androidで400 Bad Requestが出ることは多いみたいですね。Google Adsenseとか、Google Analyticsとか、そういうのが原因かもしれません。

ちなみに、デバッグ中にS氏はドコモショップに行ってOSを4.xに上げてもらったようですが、それでは解決しませんでした。

今回のことから得た教訓は……

  • 端末によって起きたり起きなかったりすると、デバッグ大変。
  • Androidはマジで辛い

おまけ: client_body_buffer_sizeも設定した

今回の件でログをあさったところ、大量のエラーが出ていました。

an upstream response is buffered to a temporary file /var/cache/nginx/fastcgi_temp/1/02/0000000021 while reading upstream

PHP-FPMと通信するときにバッファに乗り切らないとファイルI/Oが発生するたみたいです。よって、client_body_buffer_sizeを大きめに設定。どうも、ページサイズの倍ぐらいないとダメっぽかったので、次のようにしました。

http{
    client_body_buffer_size 512k;
}

ここら辺はわりと適当なので、参考リンクなども熟読してください。終わり。

マスタリングNginx

価格¥392

順位638,046位

Dimitri Aivaliotis

翻訳高橋 基信

発行オライリージャパン

発売日2013 年 10 月 26 日

今これ読んでる。

Amazonを開く

Supported by amazon Product Advertising API

すべての投稿を見る

高橋文樹ニュースレター

高橋文樹が最近の活動報告、サイトでパブリックにできない情報などをお伝えするメーリングリストです。 滅多に送りませんので、ぜひご登録お願いいたします。 お得なダウンロードコンテンツなども計画中です。