32

在播放框架 1 中,您可以在路由文件中使用类似这样的内容(查看http://www.playframework.org/documentation/1.2.5/routes#syntax上的文档)

GET     /clients/?       Clients.index

这样路由将匹配 /api/clients 以及 /api/clients/

如何在游戏框架 2 中实现相同的目标?

4

6 回答 6

71

从 SEO 的角度来看,相同的链接与trailing slash没有它的链接不同。强烈建议始终使用一种模式(拖尾或非拖尾链接)。

虽然有不同的学校,但最重要的是从“错误”的 URL 到正确的 URL 进行 301 重定向。您可以在 Play 中使用“跨越多个 / 的动态部分”轻松实现它。

我个人更喜欢不拖尾的版本,可能是因为在 Play 中实现它就像写几行简单的行。将此规则添加到您的路由文件中,在开头的某处(保留斜杠 - 这很重要,因为它不被视为跨组中的下一个斜杠,并且允许轻松匹配尾随 URL):

GET  /*path/  controllers.Application.untrail(path: String)

然后你可以在控制器中进行重定向 - 到参数,所以最后没有斜杠:

Java

public static Result untrail(String path) {
   return movedPermanently("/" + path);
}

Scala

def untrail(path: String) = Action { 
  MovedPermanently("/" + path)
}

到现在为止,所有以斜线结尾的路由都将被重定向到无尾版本。简单的 :)

当然,强烈建议使用反向路由器来生成正确的 URL - 以最大限度地减少冗余重定向。此外,如果您在某处(即在某些 JS 或外部应用程序中)对 URL 进行硬编码,最好编写正确的 URL,而不是每次都转换它们。如果您计划发布一些公共 API,请在文档中记下您的应用程序更喜欢哪种模式,这样开发人员就会收到警告,并且(也许)会准备正确的调用。

更重要的是 - 这对路线最重要,GET因为它们是客户端操纵的主题。在使用POST,PUTDELETE其他您不需要(或者更确切地说,您不应该)关心重定向时,因为它们不能被用户更改,因此您需要记住您选择的方式。如果呼叫错误,即。对于 POST,只返回 404 错误 - 所以第三部分应用程序的开发者将有义务使用正确的结尾。

于 2012-11-02T13:31:08.790 回答
9

我设法想出了一些东西,它并不像我希望的那么简单,但这也不是火箭科学

import play.api.mvc.RequestHeader

import play.api.Play.current

class NormalizedRequest(request: RequestHeader) extends RequestHeader {

  val headers = request.headers
  val queryString = request.queryString
  val remoteAddress = request.remoteAddress
  val method = request.method

  val path = request.path.stripSuffix("/")
  val uri = path + {
    if(request.rawQueryString == "") ""
    else "?" + request.rawQueryString
  }
}

object NormalizedRequest {
  def apply(request: RequestHeader) = new NormalizedRequest(request)
}

然后我在 Global.scala 中像这样使用它

override def onRouteRequest(request: RequestHeader): Option[Handler] = {
  super.onRouteRequest(NormalizedRequest(request))
}
于 2012-11-02T06:26:34.993 回答
6

更新了 @opensas 和 @lloydmeta 的示例以进行 play 2.5

/**
  * HttpRequestHandler that removes trailing slashes from requests.
  */
class TrailingSlashNormaliserHttpRequestHandler(router: Router, errorHandler: HttpErrorHandler, configuration: HttpConfiguration, filters: HttpFilters) extends HttpRequestHandler {

  private val default = new DefaultHttpRequestHandler(router, errorHandler, configuration, filters)

  override def handlerForRequest(request: RequestHeader): (RequestHeader, Handler) = {
    default.handlerForRequest(removeTrailingSlash(request))
  }

  private def removeTrailingSlash(origReq: RequestHeader): RequestHeader = {
    if (origReq.path.endsWith("/") && origReq.path != "/") {
      val path = origReq.path.stripSuffix("/")
      if (origReq.rawQueryString.isEmpty) {
        origReq.copy(path = path, uri = path)
      }else {
        origReq.copy(path = path, uri = path + s"?${origReq.rawQueryString}")
      }
    } else {
      origReq
    }
  }
}

有关如何应用处理程序的说明,请参阅https://www.playframework.com/documentation/2.5.x/ScalaHttpRequestHandlers

于 2016-05-30T09:15:44.697 回答
2

对于 Play 2.8,此处对其他答案的更新:

import play.api.OptionalDevContext
import play.api.http._
import play.api.mvc.{Handler, RequestHeader}
import play.api.routing.Router
import play.core.WebCommands

import javax.inject.Inject

class TrailingSlashHandler @Inject() (
  webCommands: WebCommands,
  optDevContext: OptionalDevContext,
  router: Router,
  errorHandler: HttpErrorHandler,
  configuration: HttpConfiguration,
  filters: HttpFilters
) extends DefaultHttpRequestHandler(
    webCommands,
    optDevContext,
    router,
    errorHandler,
    configuration,
    filters
  ) {

  override def handlerForRequest(request: RequestHeader): (RequestHeader, Handler) =
    super.handlerForRequest(removeTrailingSlash(request))

  private def removeTrailingSlash(originalRequest: RequestHeader): RequestHeader =
    if (originalRequest.path.endsWith("/") && originalRequest.path != "/") {
      val normalizedPath = originalRequest.path.stripSuffix("/")
      val normalizedUri =
        if (originalRequest.queryString.isEmpty) originalRequest.target.uriString.stripSuffix("/")
        else originalRequest.target.uriString.replaceFirst("/\\?", "?")
      originalRequest.withTarget(
        originalRequest.target
          .withPath(normalizedPath)
          .withUriString(normalizedUri)
      )
    } else {
      originalRequest
    }
}

然后只需通过将其放入您的 conf 中进行注册:play.http.requestHandler = your.package.here.TrailingSlashHandler

于 2021-08-10T23:59:26.160 回答
1

这是基于opensas 的回答,只是简化了一点以重用 Play 的内置copy方法,RequestHeader以便RequestHeader保留原始内容中的所有内容,如 id、标签、版本、安全等。

import play.api.GlobalSettings
import play.api.mvc.{Handler, RequestHeader}

trait TrailingSlashNormaliser extends GlobalSettings {

  def removeTrailingSlash(origReq: RequestHeader): RequestHeader = {
    if (origReq.path.endsWith("/")) {
      val path = origReq.path.stripSuffix("/")
      if (origReq.rawQueryString.isEmpty)
        origReq.copy(path = path, uri = path)
      else
        origReq.copy(path = path, uri = path + s"?${origReq.rawQueryString}")
    } else {
      origReq
    }
  }

  override def onRouteRequest(request: RequestHeader): Option[Handler] = 
    super.onRouteRequest(removeTrailingSlash(request))

}

/**
 * Global object that removes trailing slashes from requests.
 */
object Global extends TrailingSlashNormaliser
于 2014-11-12T01:27:37.543 回答
0

在您的路线文件中添加该条目两次。一个带斜线,一个不带。

于 2012-11-02T04:45:21.333 回答