3

我有一个应用程序,需要我为 HEAD 和 GET 动词定义一个动作。另一个应用程序(Mozilla Open Badges)使用两个 HTTP 请求调用我的应用程序。它首先使用 HEAD 来验证我的 URL 看起来是否返回了正确类型的响应,然后对同一 URL 使用 GET 来获取内容。以下方法有效:

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

...这行得通,但违反了 DRY(不要重复自己)。

我更喜欢这样的东西:

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

...但这是不允许的。如果 GET 免费为您提供 HEAD,我也会很高兴,但我可能不明白阻止 HEAD 执行 GET 操作的原因。

我想冗余的 Path-to-Action 定义并不是世界末日,但我喜欢尽可能保持代码整洁。

根据 HEAD 的 W3C 规范 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html),我相信 Play Framework 2 的行为不正确,因为不允许在为 GET 定义的路由上调用 HEAD:

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+ 中,不可能使用通配符动词(如*ANY或多值)(这可能是您的解决方案),因此在这种情况下,您使用的“ DRY 违规”只是官方方式。

编辑

其实你可以尝试另一种方法:

  • 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")));
}
  • 和文件路由文件末尾的两个路由 HEAD

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

PS 如果您想在 Scala 中编写类似的东西,那就太好了 :)

于 2013-01-10T07:56:40.623 回答