How to Route URLs in Play 2.0 so They're Indifferent to an Ending Slash

Go To StackoverFlow.com

12

Can I capture the following two routes in a single line?

GET     /game                    controllers.Main.app.gamelist
GET     /game/                   controllers.Main.app.gamelist
2012-04-04 04:00
by Jacob Groundwater
There is a solution on Play 2.x posted here: http://stackoverflow.com/a/13196239/42228 - Eneko Alonso 2013-08-04 03:40


6

This is currently not supported and a ticket has been submitted to the issue tracker. There is also a discussion regarding this (including some workarounds) on Google Groups.

Hopefully this will be implemented in some smart way soon.

2012-04-04 08:17
by Franz
I marked you correct, however if this gets solved we should probably update your answer at a later date - Jacob Groundwater 2012-04-05 00:57


5

If you are using playframework 1.x then it is:

GET /game/? controllers.Main.app.gamelist
2012-04-04 04:12
by Gelin Luo
Thanks, I'm using version 2, whoops forgot to add 2.0 to the title - Jacob Groundwater 2012-04-04 06:05
I should add, this method doesn't seem to work in Play 2. - Jacob Groundwater 2012-04-04 07:58


5

Whilst this doesn't seem to be supported at the moment, it can be achieved by overriding onRouteRequest in Global.scala

We're doing it like this:

import play.api._
import play.api.mvc.{Handler, RequestHeader, Action, Controller}


object TrailingSlashRedirector extends Controller {
  def redirect(request: RequestHeader) = Action {
    Redirect(request.path.dropRight(1), request.queryString, 301)
  }
}

object Global extends GlobalSettings {

  override def onRouteRequest(request: RequestHeader): Option[Handler] = {

    val EndsWithASlash= """/(.*)/$""".r

    request.path match {  
      case EndsWithASlash(_) => Some(TrailingSlashRedirector.redirect(request))
      case _ => super.onRouteRequest(request)
    }

  }  

}
2012-10-18 22:15
by Mike Parker


3

(Might be late for Jacob, but someone might find this useful)

I had this problem as well, here's my workaround:

I put at the END of my routes the following line (this way, it matches urls that didn't match anything else)

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

And here's my Application.appendSlash:

public static Result appendSlash(String path) {
char ending = path.charAt(path.length() -1 );
if (ending != '/')
    return redirect('/' + path + '/');
else
    return notFound();
}

You may want to add your 404 Not Found view as a paramer to notFound()

Hope this helps

Davide

EDIT: Just one thing: this will work for common browser navigation (if someone types the url but forgets the trailing '/'), but it will NOT work with ajax or otherways automated requests: for that you will anyway have to type the complete url.

2012-05-06 18:06
by Davide
Upvoted anyways, I appreciate the answer - Jacob Groundwater 2012-05-06 19:23


2

Another possibility is to put this into your Global-Object:

If a route with a trailing slash is not found it tries one with the trailing slash removed.

The routes file just has route without trailing slashes...

@Override
public Result onHandlerNotFound(Http.RequestHeader requestHeader) {
    if (hasTrailingSlash(requestHeader.path())) {
        return Action.redirect(removeLastChar(requestHeader.path()));
    }
    return super.onHandlerNotFound(requestHeader);
}

private static String removeLastChar(String value) {
    return value.substring(0, value.length() - 1);
}

private static boolean hasTrailingSlash(String value) {
    return value != null && value.endsWith("/");
}
2012-07-12 15:04
by Martin


1

Here's the solution I've found

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)
}

ans then I use it like this in Global.scala

override def onRouteRequest(request: RequestHeader): Option[Handler] = {
  super.onRouteRequest(NormalizedRequest(request))
}

And here's a similar question: play framework2: remove trailing slash from urls

2012-11-02 21:37
by opensas
Is it possible to solve it without redirect - Sergey 2016-06-21 09:07
Ads