web-dev-qa-db-ja.com

proxy_passでクエリパラメータをデコードするnginxを避けます(AllowEncodedSlashes NoDecodeと同等)

いくつかのTomcatの前で、nginxをロードバランサーとして使用します。着信リクエストでは、クエリパラメータをエンコードしています。ただし、リクエストがTomcatに到着すると、パラメーターはデコードされます。

nginxへの着信リクエスト:

curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http%3A%2F%2Fwww.google.com%2F"

tomcatへの着信リクエスト:

curl -i "http://server/1.1/json/T;cID=1234;pID=1200;rF=http:/www.google.com/"

その場合、Tomcatは405エラーをスローするため、要求パラメーターを変換したくありません。

私のnginx設定は次のとおりです:

upstream tracking  {
    server front-01.server.com:8080;
    server front-02.server.com:8080;
    server front-03.server.com:8080;
    server front-04.server.com:8080;
}

server {
    listen 80;
    server_name tracking.server.com;
    access_log /var/log/nginx/tracking-access.log;
    error_log  /var/log/nginx/tracking-error.log;

    location / {
        proxy_pass  http://tracking/webapp;
    }
}

現在のApacheロードバランサーの構成には、エンコードされたパラメーターを保持する AllowEncodedSlashes ディレクティブがあります。

AllowEncodedSlashes NoDecode

Apacheからnginxに移行する必要があります。

私の質問はこの質問とは正反対です: proxy_pass でnginxがクエリパラメータをエスケープしないようにします

23

私は最終的に解決策を見つけました: $request_uriパラメータ

location / {
    proxy_pass  http://tracking/webapp$request_uri;
}

そのようにして、元のリクエストでエンコードされた文字はnotデコードされません。つまり、プロキシされたサーバーにそのまま渡されます。

41

Jeanの答え は良いですが、サブロケーションでは機能しません。その場合、より一般的な答えは次のとおりです。

location /path/ {
  if ($request_uri ~* "/path/(.*)") {
    proxy_pass http://tracking/webapp/$1;
  }
}
13
user1338062

Nginx proxy_pass ディレクティブには、文書化されたオプションが1つあります

未処理の形式でURIを送信する必要がある場合、ディレクティブproxy_passを使用する必要がありますURI部分なし

location  /some/path/ {
  proxy_pass   http://127.0.0.1;
}

あなたの場合、このようになります。リクエストURIが上流サーバーに渡されることを心配しないでください

location / {
    proxy_pass  http://tracking;
}

それが役に立てば幸い。

10
Casey

一般に$uri "normalisation"として知られているURLデコードは、nginxのドキュメント内で、バックエンドIFFの前に発生することに注意してください。

  • 末尾のスラッシュだけがすべて単独である場合でも、proxy_pass自体内でURIを指定するか、

  • または、URIは処理中に変更されます(例:rewriteを使用)。


両方の条件は http://nginx.org/r/proxy_pass (emphasis mine)で明示的に文書化されています:

  • proxy_passディレクティブがとURIで指定されている場合、リクエストが渡されたときサーバーに対して、場所に一致するnormalizedリクエストURIの部分は、指定されたURIに置き換えられます指令で

  • proxy_passが指定されている場合URIなし、リクエストURIはサーバーに渡されます元のリクエストが処理されるときにクライアントによって送信されたものと同じ形式で、orフルnormalizedリクエストURIが渡されるwhen処理変更されたURI


解決策は、フロントエンドとバックエンドの間でURLを変更する必要があるかどうかによって異なります。

  • URIの変更が必要ない場合:

    # map `/foo` to `/foo`:
    location /foo {
        proxy_pass  http://localhost:8080;  # no URI -- not even just a slash
    }
    
  • それ以外の場合、フロントエンドの/apiをバックエンドの/appと交換またはマッピングする必要がある場合、 $request_uri から元のURIを取得できます。 =変数、およびDFAに似た$uri変数に対してrewriteディレクティブを使用します(ところで、rewrite DFAアクションをさらに必要とする場合は、 mdoc.s )。誰かが2番目の書き換えルールを回避しようとする場合、return 400のようなものと一致しないため、//api/部分が必要であることに注意してください。

    # map `/api` to `/app`:
    location /foo {
        rewrite  ^  $request_uri;            # get original URI
        rewrite  ^/api(/.*)  /app$1  break;  # drop /api, put /app
        return 400;   # if the second rewrite won't match
        proxy_pass    http://localhost:8080$uri;
    }
    
  • バックエンドにプレフィックスを追加するだけの場合は、$request_uri変数をすぐに使用できます。

    # add `/webapp` to the backend:
    location / {
        proxy_pass    http://localhost:8080/webapp$request_uri;
    }
    

関連する回答 もご覧ください。これは、上記と同様のコードのいくつかのテスト実行を示しています。

6
cnst