53
votes

Is it possible to restrict a Symfony 2 route for XHR requests only? I want to declare routes, which are only accessible via AJAX.

I do not want to put some extra lines into each AJAX-specific-actions like that:

if ($request->isXmlHttpRequest()) {
    // do something
} else {
    // do something else
}

I want to define:

  • one rule for AJAX requests
  • one rule for GET/POST requests to the same URL

in order to get around having conditions like above.

6
Why? The data they expose won't be available to anyone who couldn't get at it anyway.Quentin
Why would you want to do that?Elnur Abdurrakhimov
Want to restrict access to the route only for XHR requests.Chris
@crudolf — If someone (or two people) ask you why you want to do X, then just repeating that you want to do X is not helpful.Quentin
@Quentin -- thanks. I have added a reason, why I am asking the question.Chris

6 Answers

102
votes

I know this question is a bit older but meanwhile a new way to achieve this was introduced in Symfony 2.4.

Matching Expressions

For an ajax restriction it would look like this:

contact:
    path:     /contact
    defaults: { _controller: AcmeDemoBundle:Main:contact }
    condition: "request.isXmlHttpRequest()"

Also possible in Annotation:

/**
 * ContactAction
 *
 * @Route("/contact", name="contact", condition="request.isXmlHttpRequest()")
 */
10
votes

My advice would be to define your own router service instead of default, which would extend from Symfony\Bundle\FrameworkBundle\Routing\Router, and redefine method resolveParameters() with implementing your own logic for handling additional requirements.

And then, you could do something like this in your routing:

your_route:
    pattern:  /somepattern
    defaults: { somedefaults }
    requirements:
        _request_type:  some_requirement
3
votes

I'm not sure that you can prevent the request taking place, however you can check for an XHR request in the Controller by checking the current Request

The code would look like this:

if ($request->isXmlHttpRequest()) {
    // ...
}

This is not 100% reliable, due to among other things, browser inconsistencies and the possibility of proxy interference. However it is the predominant method of checking for an asynchronous request and is recommended by many. If you are cr

URL Parameter

An alternative would be to add a parameter in your URL to identify the request as asynchronous. This is achieved by adding ?ajax=1 to your URL. Then, check for the parameter with:

$AjaxRequest = $request->getParameter('ajax');
If($AjaxRequest == 1) {
    //...
}

Of course, at this point you could also create a specific Route e.g. /ajax/index/.

2
votes

No, you cannot. It is not depend on which framework you are using, AJAX requests basically are just requests to a server. There is no 100% reliable solution, just "hacks".

1
votes

What you're looking for does not exist in Symfony routing configuration.

Request::isXmlHttpRequest is even not 100% reliable, and checks HTTP headers put by your JavaScript library :

It works if your JavaScript library set an X-Requested-With HTTP header. It is known to work with Prototype, Mootools, jQuery.

0
votes

You can use the requirements for reach the described result.
So, suppose that you're defining routes onto yml format, you have to do something like this

my_route:
  pattern:  /path/to/route
  defaults: { _controller: CompanyBundle:Controller:Action, _format: html }
  requirements:
      _format:  xmlhttp /* not sure about the correct format because
                           i've never checked about */

And you can, of course, use _method: POST or _method: GET