web-dev-qa-db-ja.com

JavaサーブレットアプリケーションでHTTP 201応答のLocationヘッダーを設定する適切な方法は何ですか

HTTP 201 "Created"応答をクライアントに送信する次のコードを検討してください。

    String url = "/app/things?id=42"; // example
    response.setStatus(HttpServletResponse.SC_CREATED);
    response.setContentType("text/plain");
    response.setHeader("Location", url);
    response.getWriter().print(url);

クライアントに、新しい「もの」が作成され、URL /app/things?id=42。問題は、このURLが相対的であることです。これはJSPに最適で、次のように記述できます。

<img src="<c:url value="/things?id=42" />" />

次のHTMLが生成されます。

<img src="/app/things?id=42" />

これがWebアプリに必要なものです。

しかし、201応答のLocationヘッダーにそれが必要だとは思いません。 HTTP仕様 状態

14.30場所

Location response-headerフィールドは、要求の完了または新しいリソースの識別のために、受信者をRequest-URI以外の場所にリダイレクトするために使用されます。 201(作成済み)応答の場合、ロケーションは、リクエストによって作成された新しいリソースのロケーションです。 3xx応答の場合、場所は、リソースへの自動リダイレクトのためのサーバーの優先URIを示す必要があります。フィールド値は、単一の絶対URIで構成されます。

       Location = "Location" ":" absoluteURI

例は次のとおりです。

       Location: http://www.w3.org/pub/WWW/People.html

私の質問は、サーブレットの適切な方法で、その相対URLをLocationヘッダーの絶対URLに変換する方法です。

私は以下を使用することを信じない:

request.getServerName() + ":" + request.getServerPort() + url;

正しい解決策です。正しい出力を生成する標準的な方法が必要です(URLの書き換えなどを適用できるようにするため)。ハックを作りたくありません。

34
les2

絶対パスを送信するだけです。 絶対URIへの制限はRFC 2616の既知の欠陥であり、HTTPbisで修正されます( http://trac.tools.ietf.org/wg/httpbis/trac/ticket/185 を参照) 。

RFC 7231仕様に相対URIを含むことに注意してください。 URI !

22
Julian Reschke

ジュリアン・レシュケのアドバイスに従い、仕様に違反することにしました!少なくとも次のコメントを追加しました。

        /* Note: strictly speaking (per section 14.30 of RFC 2616), the Location header 
         * requires an *absolute URI*. However, in practice, many web 
         * applications send an *absolute path* instead. This is interoperable, 
         * that is, works in popular web browsers  (according to 
         * http://en.wikipedia.org/wiki/HTTP_location).
         * 
         * As the information required to set the Location header to an absolute URI
         * is not generally available to a Servlet, we go with the flow and send
         * an absolute path instead (in violation of RFC 2616).
         * 
         * There is an issue filed with Hypertext Transfer Protocol Bis (httpbis) 
         * working group to resolve this problem here:
         * http://trac.tools.ietf.org/wg/httpbis/trac/ticket/185
         */
        response.setHeader("Location", url);

絶対URIを自分で送信したくないのは、ロードバランサーや他の運用インフラストラクチャの背後で問題が発生したためです。開発モードでは「http:// localhost:8080/foo」は正常に動作する傾向がありますが:))

今ジュリアンの答えを受け入れます...

4
les2

残念ながら、サーブレットAPIは、コンテキストルートまでの絶対URLを直接返すメソッドを提供しません。そのために getRequestURL()getRequestURI() および getContextPath()

String absoluteContextRootURL = request.getRequestURL().toString().replace(request.getRequestURI().substring(1), request.getContextPath());
4
BalusC

JAX RSを使用している場合、_javax.ws.rs.core.Response_にメソッドがあります。これは 相対URLを自動的に変換します

public static Response.ResponseBuilder created(Java.net.URI location)

作成されたリソースの新しいResponseBuilderを作成し、指定された値を使用してロケーションヘッダーを設定します。

パラメーター:

  • location-新しいリソースのURI。相対URIが指定されている場合、要求URIを基準にして解決することで絶対URIに変換されます。

ただし、JAX RS実装CXFには 間違った絶対URLにつながる というバグがあることに注意してください。

4
oberlies

あなたが試すかもしれません

new URL(new URL(request.getRequestURL().toString()), url).toString();

少なくとも..またはその他の奇妙な点。それ以外は、文字列操作よりはるかに優れているとは思いません。