在播放框架 1 中,您可以在路由文件中使用类似这样的内容(查看http://www.playframework.org/documentation/1.2.5/routes#syntax上的文档)
GET /clients/? Clients.index
这样路由将匹配 /api/clients 以及 /api/clients/
如何在游戏框架 2 中实现相同的目标?
在播放框架 1 中,您可以在路由文件中使用类似这样的内容(查看http://www.playframework.org/documentation/1.2.5/routes#syntax上的文档)
GET /clients/? Clients.index
这样路由将匹配 /api/clients 以及 /api/clients/
如何在游戏框架 2 中实现相同的目标?
从 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
,PUT
和DELETE
其他您不需要(或者更确切地说,您不应该)关心重定向时,因为它们不能被用户更改,因此您需要记住您选择的方式。如果呼叫错误,即。对于 POST,只返回 404 错误 - 所以第三部分应用程序的开发者将有义务使用正确的结尾。
我设法想出了一些东西,它并不像我希望的那么简单,但这也不是火箭科学
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))
}
更新了 @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
对于 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
这是基于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
在您的路线文件中添加该条目两次。一个带斜线,一个不带。