3

HEAD 動詞と GET 動詞の両方に対してアクションを定義する必要があるアプリがあります。別のアプリ (Mozilla Open Badges) が、2 つの HTTP リクエストを使用して私のアプリを呼び出します。最初に HEAD を使用して、URL が正しいタイプの応答を返しているように見えることを確認し、次に同じ URL に対して GET を使用してコンテンツをフェッチします。次のアプローチが機能します。

GET   /assertion                        controllers.Assertion.index
HEAD  /assertion                        controllers.Assertion.index

...これは機能しますが、DRY 違反です (Don't Repeat Yourself)。

私は次のようなものを好むだろう:

(GET, HEAD)   /assertion                        controllers.Assertion.index

...しかし、これは許可されていません。GET が無料で HEAD を提供してくれたら嬉しいのですが、GET アクションのために HEAD をブロックする理由が理解できないかもしれません。

冗長なアクションへのパスの定義は世界の終わりではないと思いますが、可能な限りコードをきれいに保ちたいと思っています。

HEAD の W3C 仕様 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) に基づいて、GET 用に定義されたルートで HEAD 呼び出しを許可しないため、Play Framework 2 が正しく動作していないと私は信じています。

9.4 HEAD

The HEAD method is identical to GET except that the server MUST NOT return a 
message-body in the response. The metainformation contained in the HTTP headers in
response to a HEAD request SHOULD be identical to the information sent in response 
to a GET request. This method can be used for obtaining metainformation about the
entity implied by the request without transferring the entity-body itself. This 
method is often used for testing hypertext links for validity, accessibility, and 
recent modification.
4

1 に答える 1

2

Play 2.0+ ではワイルドカード動詞 ( *orANYまたは多値など) を使用することはできません (これは解決策になる可能性があります) 。

編集

実際には、別のアプローチを試すことができます。

  • routesファイルの最後に' catch-all HEAD ' rulezを置きます
  • HEAD /path' catch-all ' のルートが指定されていない場合は、それをautoHead(path: String)アクションに送信します。
  • WebServicesを使用して、リクエストからGETルートのバージョンにすべてのヘッダーを転送し、レスポンスを取得してヘッダーのみを返すことができます。

このアプローチの動作サンプル (Java のみ) をplay-simple-restサンプル アプリに追加しました。リダイレクトで重要なことは次のとおりです。

public static Result autoHead(String originalPath) throws IllegalAccessException {

    WS.WSRequestHolder forwardedRequest = WS.url("http://" + request().host() + request().path());
    // this header will allow you to make additional choice i.e. avoid tracking the request or something else
    // see condition in index() action
    forwardedRequest.setHeader("X_FORWARD_FROM_HEAD", "true");

    // Forward original headers
    for (String header : request().headers().keySet()) {
        forwardedRequest.setHeader(header, request().getHeader(header));
    }

    // Forward original queryString
    for (String key : request().queryString().keySet()) {
        for (String val : request().queryString().get(key)) {
            forwardedRequest.setQueryParameter(key, val);
        }
    }

    // Call the same path but with GET
    WS.Response wsResponse = forwardedRequest.get().get();

    // Set returned headers to the response
    for (Field f : Http.HeaderNames.class.getFields()) {
        String headerName = f.get(null).toString();
        if (wsResponse.getHeader(headerName) != null) {
            response().setHeader(headerName, wsResponse.getHeader(headerName));
        }
    }

    return status(wsResponse.getStatus());
}
public static boolean forwardedFromHead() {
    return (request().getHeader("X_FORWARD_FROM_HEAD") != null && "true".equals(request().getHeader("X_FORWARD_FROM_HEAD")));
}
  • ファイルルートファイルの最後にある2つのルートHEAD

    HEAD    /               controllers.Application.autoHead(originalPath:String ?= "/")
    HEAD    /*originalPath  controllers.Application.autoHead(originalPath:String)
    

PS Scalaで似たようなものを書きたいなら、それはいいでしょう:)

于 2013-01-10T07:56:40.623 に答える