web-dev-qa-db-ja.com

HTTP要求とHTTPS要求の両方について、サーブレットで完全なURLとクエリ文字列を取得します

要求されたURLまたはフルパスを取得するコードを書いています。私はこのコードを書きました:

HttpServletRequest request;//obtained from other functions
String uri = request.getRequestURI();
if (request.getQueryString() != null)
    uri += "?" + request.getQueryString();

したがって、http://google.com?q=abcを参照すると、問題ありません(正しい)。しかし、https://google.comを参照すると問題が発生します。 uriの値はhttp://google.com:443google.com:443であるため、プログラムはHTTPSが使用されているときだけではありません。

また、request.getRequestURL().toString()の出力は同じです。

解決策は何ですか?

69
progrrammer

設計上、 getRequestURL() は完全なURLを提供し、クエリ文字列のみが欠落しています。

HttpServletRequest では、以下のメソッドを使用してURIの個々の部分を取得できます。

// Example: http://myhost:8080/people?lastname=Fox&age=30

String uri = request.getScheme() + "://" +   // "http" + "://
             request.getServerName() +       // "myhost"
             ":" +                           // ":"
             request.getServerPort() +       // "8080"
             request.getRequestURI() +       // "/people"
             "?" +                           // "?"
             request.getQueryString();       // "lastname=Fox&age=30"
  • .getScheme()は、"https"要求である場合はhttps://domainを提供します。
  • .getServerName()は、http(s)://domaindomainを提供します。
  • .getServerPort()はポートを提供します。

以下のスニペットを使用します。

String uri = request.getScheme() + "://" +
             request.getServerName() + 
             ("http".equals(request.getScheme()) && request.getServerPort() == 80 || "https".equals(request.getScheme()) && request.getServerPort() == 443 ? "" : ":" + request.getServerPort() ) +
             request.getRequestURI() +
            (request.getQueryString() != null ? "?" + request.getQueryString() : "");

上記のこのスニペットは完全なURIを取得し、デフォルトが使用されている場合はポートを非表示にし、後者が提供されていない場合は"?"とクエリ文字列を追加しません。


プロキシされたリクエスト

リクエストがプロキシを通過する場合、スキームが変更される可能性があるため、X-Forwarded-Protoヘッダーを確認する必要があることに注意してください。

request.getHeader("X-Forwarded-Proto")

また、一般的なヘッダーはX-Forwarded-Forであり、プロキシIPではなく元の要求IPを示します。

request.getHeader("X-Forwarded-For")

プロキシ/ロードバランサーの構成を自分で行う場合は、転送時にこれらのヘッダーが設定されていることを確認する必要があります。

147
acdcjunior

単に使用:

String Uri = request.getRequestURL()+"?"+request.getQueryString();
10
sumitkanoje

サーバー側でURLを作成しようとしたときにHTTPSリクエストがHTTPになるという事実は、SSL暗号化を前もってバックエンドサービスにオフロードするプロキシ/ロードバランサー(nginxpoundなど)があることを示していますHTTP

その場合は、確認してください、

  1. ヘッダーが正しく転送されるようにプロキシが設定されているかどうか(HostX-forwarded-protoX-forwarded-forなど).
  2. サービスコンテナ(Tomcatなど)が前のプロキシを認識するように設定されているかどうか。たとえば、Tomcatでは、secure="true" scheme="https" proxyPort="443"属性をConnectorに追加する必要があります
  3. コードまたはサービスコンテナがヘッダーを正しく処理しているかどうか。たとえば、Tomcatschemeに追加すると、remoteAddrRemoteIpValveEngineなどの値を自動的に置き換えます。 ( 構成ガイドJavaDoc を参照)、コード内のこれらのヘッダーを手動で処理する必要はありません。

request.getRequestURI()またはrequest.getRequestURL()_が発信元URLを構築しようとすると、プロキシヘッダー値が正しくないため、出力が正しくない可能性があります。

1
dancnfoo