Rewriting URL in play framework - redirect and route Subscribe Pub

Note - this is a year-old post that somehow remained in "draft" state. It's applicable to Play Framework up to 2.4 (uses Global).

If you wanted to host multiple websites on your play server backend, you'll likely need to rewrite URLs, depending on the host the request was originally sent to.

You could use Apache rewriting rules, but that means logging in to your router box, updating the rules and restarting the server.

Alternatively, you could have a separate rewriting configuration, loaded by your backend and do the redirect within the backend. The examples here use a redirect, but you could also just change the request (filter) and handle it locally).

Here's how to intercept the play framework routing and redirect, without having to worry about this or that controller or mapping rules.

The idea is to overwrite Global.onRouteRequest, much like decribed in https://www.playframework.com/documentation/2.0/ScalaInterceptors

Here's my final code, to re-route one host to another, in case your server hosts multiple websites:

  override def onRouteRequest(request: RequestHeader): Option[Handler] = {
    if (! request.path.startsWith( "/assets/"))
      cdebug << ("ROUTE_REQ.START: " + request.toString)

    /** get the host that was forwarded here - used for multi-site hosting */
    val host =  request.headers.get("X-FORWARDED-HOST")

    val res = host.filter(_ == "www.myhost.com").map {
      Some(EssentialAction {rh=>
      Action { rh:play.api.mvc.RequestHeader =>
        Results.Redirect("http://www.myotherhost.com")
        }.apply(rh)
      })
    } else {
      super.onRouteRequest(request)
    }

    res
  }

Note that the X-FORWARDED-HOST is added by the apache proxy - you surely use one if your website is public facing.

And that's all there is to it. If you want to include or rewrite the path ratehr than the server, it's available in request.path so

  private def rewrite (path:String) : Option[String] = 
    if(path == "old.url") Some("new.url")
    else None

  override def onRouteRequest(request: RequestHeader): Option[Handler] = {
    rewrite(request.path)).map {newPath=>
     EssentialAction {rh=>
      Action { rh:play.api.mvc.RequestHeader =>
        Results.Redirect(newPath)
        }.apply(rh)
      }
    } orElse {
      super.onRouteRequest(request)
    }
  }

Enjoy!

p.s. The convoluted EssentialAction into Action construct is a result of two things: my laziness and my favorite scala programming technique: "aligning types" !


Was this useful?    

By: Razie | 2016-09-21 | Tags: post , scala , play , playframework , routing


See more in: Cool Scala Subscribe

Viewed 8954 times ( | History | Print ) this page.

You need to log in to post a comment!