nginx プロキシでの複数の 302 応答の解決策 (nginx Follow 302)

nginx プロキシでの複数の 302 応答の解決策 (nginx Follow 302)

proxy_intercept_errors と recursive_error_pages を使用して複数の 302 をプロキシする

302 は、HTTP プロトコルで頻繁に使用されるステータス コードです。これは複数のリダイレクト方法の 1 つであり、その意味は「一時的に移動」と解釈されることがよくあります。ちなみに、302 は実際には誤用 (303 や 307 と混在) によりよく使用されます。HTTP/1.1 では、そのセマンティクスは「Found」です。

302 は、非常に明白な場合もあれば、非常に隠れている場合もあります。最も単純なケースは、ブラウザに URL A を入力すると、ブラウザのアドレス バーが自動的に B にジャンプし、Web ページが開く場合です。この状況は 302 である可能性が最も高くなります。

Web ページに埋め込まれたプレーヤーでは、より微妙な状況が発生することがよくあります。例えば、Youku の動画再生ページを開くと、パケットをキャプチャして観察すると、302 の影が見つかることが多いです。ただし、これらの URL はブラウザで直接開かれないため、ブラウザのアドレス バーには変更が表示されません。もちろん、これらの特定の URL を具体的に選択してブラウザのアドレス バーにコピーすると、引き続き確認できます。

Youkuについては前の段落で触れました。実際、ほとんどのオンライン ビデオ ウェブサイトは現在 302 を使用しています。その理由は非常に単純です。ビデオ ウェブサイトは一般にトラフィックが多く、CDN を使用します。唯一の違いは、自分で構築した CDN を使用するか、商用 CDN を使用するかです。また、302 のリダイレクト セマンティクス (繰り返しますが、302 のセマンティクスは広く誤用されています。302 を使用する場合は、おそらく 303 または 307 を使用する必要がありますが、これについては後で詳しく説明しません) により、CDN のスケジュールとうまく組み合わせることができます。

例を見てみましょう。NetEase のビデオ再生ページを開き、パッケージを取得して、302 ステータスの URL を見つけます。例えば:

http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

これをブラウザのアドレス バーにコピーすると、アドレス バーがすぐに別の URL に変わります。この URL は不確かで、次のようなものである可能性があります。

http://14.18.140.83/f6c00af500000000-1408987545-236096587/data6/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

curl ツールを使用すると、プロセス全体がより明確に表示されます。

カール -I "http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L
HTTP/1.1 302 一時的に移動しました 
サーバー: nginx 
日付: 2014 年 8 月 25 日 (月) 14:49:43 GMT 
コンテンツタイプ: text/html 
コンテンツの長さ: 154 
接続: キープアライブ 
NG: CCN-SW-1-5L2 
X-Mod名: GSLB/3.1.0 
場所: http://119.134.254.9/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4 

HTTP/1.1 302 一時的に移動しました 
サーバー: nginx 
日付: 2014 年 8 月 25 日 (月) 14:49:41 GMT 
コンテンツタイプ: text/html 
コンテンツの長さ: 154 
接続: キープアライブ 
X-Mod-Name: Mvod-Server/4.3.3 
場所: http://119.134.254.7/cc89fdac00000000-1408983581-2095617481/data4/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4 
NG: CHN-SW-1-3Y1 

HTTP/1.1 200 OK 
サーバー: nginx 
日付: 2014 年 8 月 25 日 (月) 14:49:41 GMT 
コンテンツタイプ: video/mp4 
コンテンツの長さ: 3706468 
最終更新日: 2014年8月25日 (月) 00:23:50 GMT 
接続: キープアライブ 
キャッシュ制御: キャッシュなし 
ETag: "53fa8216-388e64" 
NG: CHN-SW-1-3g6 
X-Mod-Name: Mvod-Server/4.3.3 
受け入れ範囲: バイト

ご覧のとおり、プロセス中に 302 エラーが 2 つ発生しました。

この例は今は置いておいて、別の重要な用語である「プロキシ」について話しましょう。リーダーの中には 302 タイプのリーダーもいれば、プロキシ タイプのリーダーもいるとよく冗談で言われます。 302 タイプのリーダーは、タスクが自分の手に渡るとすぐにそれを他の人に引き継ぎますが、プロキシ タイプのリーダーはタスクに参加し、すべてを完了します。

上記の例に戻ると、URL にアクセスするときに複数の 302 がある場合、これらすべての 302 を途中で非表示にする Nginx を使用したプロキシを設計する必要がある場合はどうすればよいでしょうか。

1. オリジナルプロキシ

Nginx 自体は優れたプロキシ サーバーであることはわかっています。したがって、まず、サーバー IP が 192.168.109.128 (テスト仮想マシンの 1 つ) である Nginx フォワード プロキシを設定しましょう。

初期設定は次のように簡略化されます。

サーバー{
    聞く 80;
    位置 / {
        rewrite_by_lua '
            ngx.exec("/proxy-to" .. ngx.var.request_uri)
        ';
    }

    場所 ~ /proxy-to/([^/]+)(.*) {
        proxy_pass http://$1$2$is_args$クエリ文字列;

    }
}

達成される機能は、

http://192.168.109.128/xxxxxx

プロキシにアクセスすると、xxxxxx で表される実際のサーバーにプロキシされます。

テスト結果は次のとおりです。

カール -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L
HTTP/1.1 302 一時的に移動しました 
サーバー: nginx/1.4.6 
日付: 2014 年 8 月 25 日 (月) 14:50:54 GMT 
コンテンツタイプ: text/html 
コンテンツの長さ: 154 
接続: キープアライブ 
NG: CCN-SW-1-5L2 
X-Mod名: GSLB/3.1.0 
場所: http://183.61.140.24/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4 

HTTP/1.1 302 一時的に移動しました 
サーバー: nginx 
日付: 2014 年 8 月 25 日 (月) 14:50:55 GMT 
コンテンツタイプ: text/html 
コンテンツの長さ: 154 
接続: キープアライブ 
X-Mod-Name: Mvod-Server/4.3.3 
場所: http://183.61.140.20/540966e500000000-1408983655-236096587/data1/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4 
NG: CHN-ZJ-4-3M4 

HTTP/1.1 200 OK 
サーバー: nginx 
日付: 2014 年 8 月 25 日 (月) 14:50:55 GMT 
コンテンツタイプ: video/mp4 
コンテンツの長さ: 3706468 
最終更新日: 2014年8月25日 (月) 00:31:03 GMT 
接続: キープアライブ 
キャッシュ制御: キャッシュなし 
ETag: "53fa83c7-388e64" 
NG: CHN-ZJ-4-3M4 
X-Mod-Name: Mvod-Server/4.3.3 
受け入れ範囲: バイト

プロキシが使用されているにもかかわらず、プロセスは元のアクセスと変わらないことがわかります。アクセスプロセスは次のとおりです。

http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

Nginxがリクエストをプロキシすると

http://flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

後者はすぐに 302 を返すため、プロキシとしての Nginx は 302 をクライアントに返し、クライアントはリクエストを再開して、前の 302 を繰り返します。これは問題を示しています。Nginx のプロキシのバックエンドが 302 を返すと、クライアントは Nginx プロキシから切断され、Nginx は完全なプロキシの役割を果たすことができなくなります。

2. 最初の改訂

構成ファイルを次のように変更します。

サーバー{
    聞く 80;
    位置 / {
        rewrite_by_lua '
            ngx.exec("/proxy-to" .. ngx.var.request_uri)
        ';
    }

    場所 ~ /proxy-to/([^/]+)(.*) {
        proxy_pass http://$1$2$is_args$クエリ文字列;
        エラーページ 302 = @error_page_302;

    }
    場所 @error_page_302 {
        rewrite_by_lua '
            ローカル _, _, アップストリーム http_location = string.find(ngx.var.upstream_http_location, "^http:/(.*)$")
            ngx.header["zzzz"] = "/proxy-to" .. アップストリームhttpの場所
            ngx.exec("/proxy-to" ..upstream_http_location);
        ';

    }
}

上記との違いは、error_page が使用されていることです。その目的は、プロキシ バックエンドが 302 を返すことがわかった場合、この 302 の宛先場所をクライアントに直接返すのではなく、プロキシに継続することです。そして、このロジックには再帰の意味が含まれており、最終的に 200 のアドレスに戻るまで 302 を追跡します。テスト結果は次のとおりです。

カール -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L
HTTP/1.1 302 一時的に移動しました 
サーバー: nginx/1.4.6 
日付: 2014 年 8 月 25 日 (月) 15:01:17 GMT 
コンテンツタイプ: text/html 
コンテンツの長さ: 154 
接続: キープアライブ 
NG: CCN-SW-1-5L2 
X-Mod名: GSLB/3.1.0 
場所: http://183.61.140.24/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4 

HTTP/1.1 302 一時的に移動しました 
サーバー: nginx 
日付: 2014 年 8 月 25 日 (月) 15:01:17 GMT 
コンテンツタイプ: text/html 
コンテンツの長さ: 154 
接続: キープアライブ 
X-Mod-Name: Mvod-Server/4.3.3 
場所: http://183.61.140.20/a90a952900000000-1408984277-236096587/data1/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4 
NG: CHN-ZJ-4-3M4 

HTTP/1.1 200 OK 
サーバー: nginx 
日付: 2014 年 8 月 25 日 (月) 15:01:17 GMT 
コンテンツタイプ: video/mp4 
コンテンツの長さ: 3706468 
最終更新日: 2014年8月25日 (月) 00:31:03 GMT 
接続: キープアライブ 
キャッシュ制御: キャッシュなし 
ETag: "53fa83c7-388e64" 
NG: CHN-ZJ-4-3M4 
X-Mod-Name: Mvod-Server/4.3.3 
受け入れ範囲: バイト

この変更はまだ成功していないことがわかります。

なぜ?分析の結果、@error_page_302 の場所にヘッダー印刷ステートメントを追加しましたが、テストではヘッダーが印刷されず、プロセスが @error_page_302 の場所に入っていないことがわかります。

その理由は

エラーページ 302 = @error_page_302;

デフォルトでは、error_page はこのプロセスの戻りコードです。プロキシとして、この処理では、上流サーバーの応答が正常に転送されている限り、ステータス コードは 200 になるはずです。つまり、実際に確認する必要があるのは、プロキシ自体によって返されるステータス コードではなく、プロキシのバックエンド サーバーによって返されるステータス コードです。 Nginx wiki を見ると、proxy_intercept_errors ディレクティブはまさにこれを実行します。

構文: proxy_intercept_errors on | off;
デフォルト:  
proxy_intercept_errors をオフ;
コンテキスト: http、サーバー、場所
300 以上のコードを持つプロキシ応答をクライアントに渡すか、error_page ディレクティブを使用して処理するために nginx にリダイレクトするかを決定します。

3. 2回目の改訂

サーバー{
    聞く 80;
    proxy_intercept_errors がオン;
    位置 / {
        rewrite_by_lua '
            ngx.exec("/proxy-to" .. ngx.var.request_uri)
        ';
    }
    場所 ~ /proxy-to/([^/]+)(.*) {
        proxy_pass http://$1$2$is_args$クエリ文字列;
        エラーページ 302 = @error_page_302;

    }
    場所 @error_page_302 {
        rewrite_by_lua '
            ローカル _, _, アップストリーム http_location = string.find(ngx.var.upstream_http_location, "^http:/(.*)$")
            ngx.header["zzzz"] = "/proxy-to" .. アップストリームhttpの場所
            ngx.exec("/proxy-to" ..upstream_http_location);
        ';
    }
}

以前の変更と比較すると、唯一の違いは proxy_intercept_errors ディレクティブが追加されたことです。テスト結果は次のとおりです。

カール -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L 
HTTP/1.1 302 一時的に移動しました
サーバー: nginx/1.4.6
日付: 2014 年 8 月 25 日 (月) 15:05:54 GMT
コンテンツタイプ: text/html
コンテンツの長さ: 160
接続: キープアライブ
zzzz: /proxy-to/183.61.140.24/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4

今回はさらに魔法のようです。302 ステータスを直接返して、それ以上ジャンプしません。

問題は、最初の 302 リクエストは @error_page_302 に正常に入力されるものの、後続の error_page 命令が機能しないことです。つまり、error_page はバックエンドから最初に返されたステータス コードのみをチェックし、後続のバックエンド ステータス コードはチェックし続けます。

情報を確認します。このとき、別のコマンド recursive_error_pages が役立ちます。

4. 第三次改訂

サーバー{
    聞く 80;
    proxy_intercept_errors がオン;
    recursive_error_pages オン;
    位置 / {
        rewrite_by_lua '
            ngx.exec("/proxy-to" .. ngx.var.request_uri)
        ';
    }
    場所 ~ /proxy-to/([^/]+)(.*) {
        proxy_pass http://$1$2$is_args$クエリ文字列;
        エラーページ 302 = @error_page_302;

    }
    場所 @error_page_302 {
        rewrite_by_lua '
            ローカル _, _, アップストリーム http_location = string.find(ngx.var.upstream_http_location, "^http:/(.*)$")
            ngx.header["zzzz"] = "/proxy-to" .. アップストリームhttpの場所
            ngx.exec("/proxy-to" ..upstream_http_location);
        ';
    }
}

前回と比較すると、recursive_error_pages on 命令のみが追加されました。テスト結果は次のとおりです。

カール -I "http://192.168.109.128/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4" -L 
HTTP/1.1 200 OK 
サーバー: nginx/1.4.6 
日付: 2014 年 8 月 25 日 (月) 15:09:04 GMT 
コンテンツタイプ: video/mp4 
コンテンツの長さ: 3706468 
接続: キープアライブ 
zzzz: /proxy-to/14.18.140.83/f48bad0100000000-1408984745-236096587/data6/flv.bn.netease.com/tvmrepo/2014/8/5/P/EA3I1J05P/SD/EA3I1J05P-mobile.mp4 
最終更新日: 2014年8月25日 (月) 00:21:07 GMT 
キャッシュ制御: キャッシュなし 
ETag: "53fa8173-388e64" 
NG: CHN-MM-4-3FE 
X-Mod-Name: Mvod-Server/4.3.3 
受け入れ範囲: バイト

Nginx が最終的に 200 を正常に返したことがわかります。この時点で、Nginx は実際にプロキシの役割を果たし、リクエストの複数の 302 リンクを隠し、クライアントに 1 つの最終結果のみを返します。

5. まとめ

要約すると、proxy_pass、error_page、proxy_intercept_errors、および recursive_error_pages 命令を一緒に使用することで、クライアントからのリクエストのリダイレクトの詳細を隠し、ステータス コード 200 の最終結果をユーザーに直接返すことができます。

以上がこの記事の全内容です。皆様の勉強のお役に立てれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Nginxリバースプロキシに基づく実IP取得の問題の詳細な説明
  • nginx サーバーの IP とトラフィック統計を取得する Python 実装例
  • CDN アクセラレーションを使用する際にユーザーの IP を取得するように Nginx を構成する方法の詳細な説明
  • Nginx 仮想ホスト (IP ベース) を構成する 3 つの方法の詳細な説明
  • nginx を使用して同じドメイン名で複数の Vue プロジェクトをデプロイし、リバース プロキシを使用する方法
  • nginxリバースプロキシサービスは、設定ファイルのエラーによりリソースにアクセスするときに404エラーを引き起こします。
  • nginx が複数のプロキシ層を通過して実際の送信元 IP を取得するプロセスの詳細な説明

<<:  JavaScript ステートメントの一般的な for ループの詳細な説明

>>:  シェルでパスワードなしでMySQLデータベースに素早くログインする方法

推薦する

Linuxはsttyを使用して端末の回線設定を表示および変更します。

Sttty は、Linux で端末設定を変更および印刷するための一般的なコマンドです。 1. パラ...

CSSページ下部固定を実現する8つの方法の詳細な説明

ページを書いているときに、ページの内容が小さくてフッターがページの真ん中に留まってしまうといった状況...

dockerでデプロイされたjenkinsでgitプログラムを実行する際の問題について

1. まず、gitを関連付けるときにエラーメッセージが報告されます: エラー: ビルドするリビジョン...

MySQL エラー コード 1862 の解決方法: パスワードの有効期限が切れています

ブロガーは 1 ~ 2 か月間 MySQL を使用していませんでしたが、今日この問題に遭遇しました。...

プロセスごとにネットワーク帯域幅を監視する Linux ツール Nethogs のインストールと展開

概要Linux 用のオープン ソース ネットワーク監視ツールは数多くあります。たとえば、帯域幅の使用...

データベースインデックスの知識ポイントの概要

目次ファーストルックインデックスインデックスの概念インデックスファイルの構成インデックスの役割SQL...

MySQL サーバー IO 100% 分析および最適化ソリューション

序文ストレス テスト中に、リソース使用のボトルネックによって発生する最も直接的なパフォーマンスの問題...

MySQL 5.0.96 for Windows x86 32 ビット グリーン簡易版インストール チュートリアル

MySQL 5.0 は、いくつかの「高度な機能」があるため定番となっています。これは、Windows...

Linux で仮想コンソール セッションをロックする方法

共有システムで作業しているときは、他のユーザーが自分のコンソールを覗き込んで、自分が何をしているか見...

favico.ico---ウェブサイトicoアイコン設定手順

1. 正常に生成されたアイコン ファイルをダウンロードし、名前を favico.ico に変更して、...

Linux QT Kit が見つからない、バージョンが空の問題の解決策

現在このような問題が発生しています 私の状況は、QT が動かなくなってしまったため、仮想マシンを再起...

プロフェッショナルおよび非プロフェッショナルのウェブデザイン

まず、Web ページのスタイルの形成は、主に Web ページのレイアウト設計、ページの色処理、画像と...

Dockerプライベートウェアハウスの構築とインターフェース管理の詳細な説明

1. レジストリについて公式 Docker ハブは、パブリックイメージを管理するのに適した場所です。...

ライフゲームの JavaScript 実装

目次コンセプト紹介論理的ルール完全なコード主な実装コンセプト紹介セルオートマトンとは、コンピュータの...

ナビゲーションバーのドロップダウンメニューのサンプルコードを実装するためのHTML+CSS

効果コード内の画像は自分で変更できますドロップダウンメニューのHTMLコード <ヘッダークラ​...