0

In my controller function I need to return different replies based on the accepted content type and how the request was made. But for some reason $request->header->get( 'accept' ) or $request->getRequestFormat() always returns HTML (or "text/html" respectively) although the browser has sent something different according to Firebug and Wireshark also confirms that the original request was really different.

Basically my code looks like this:

public function someControllerAction() {
  $request = $this->getRequest();

  if( $request->isXmlHttpRequest() && $request->getRequestFormat() == 'html' ) {
    // (1) Return some HTML fragment that is used to update the DOM at client side
  } else if( $request->isXmlHttpRequest() && $request->getRequestFormat() == 'json' ) {
    // (2) Return a JSON object
  } else if( $request->getRequestFormat() == 'html' ) {
    // (3) Return a full HTML page from a TWIG template
  }

  // In all other cases, return a 406 error
}

For some reason, only case (1) or case (3) are executed, because the requested format always equals HTML. I have already tried

die( var_dump( $request->header ) )

to have a look at what Symfony thinks the header was and I noticed some other minor changes in the header compared to what Wireshark tells. For example,everything is converted to lowercase.

At the moment my best guess is that somewhere in the depth of the Symfony core some kind of normalization seems to occur which also replaces the Accept-Header-Field by a default "text/html". Interestingly, the X-Requested-With-Field is not normalized away but survives.

What do I have to change that the request object returns the actual (true) header fields?

UPDATE: The result of

die( var_dump( getallheaders() ) );

shows the wrong header, too. Does Symfony manipulate the native PHP variables or does this indicate that Apache twiddles with the accept header before passing it to the PHP handler?

2 Answers 2

1

I finally figured out where the problem is. Firstly, as already mentioned in the other answer, $request->getRequestFormat() is something else. (It is hard-wired to the placeholder _format.) But it is NOT $request-getContentType() neither as discussed in the comment. The HTTP-Accept-Header can either be obtained by $request->headers->get('accept') or in an easier-to-use way by $request-> getAcceptableContentTypes(). But this is only one part of the solution, because $request->getAcceptableContentTypes() will still return an array with wrong values.

The ultimate solution is that $request MUST NOT be obtained by getRequest() BUT as the first parameter of the controller method. As I found in the Upgrade Guide to Symfony 3 getRequest() is deprecated since 2.4. It seems that getRequest() returns a different object than the one injected through the parameter and that under certain conditions the first approach does not reliably keeps the Accept-Header intact. Probably, one could call this a bug, but if getRequest() is deprecated anyway I do not bother. (BTW: Why does even the official Symfony documentation "The Book" and "The Cookbook" present examples that use a deprecated method?!).

Anyway, the fully working solution is

use Symfony\Component\HttpFoundation\Request;

public function someControllerAction( Request $request ) {
  if( $request->isXmlHttpRequest() && in_array( 'text/html', $request->getAcceptableContentTypes() ) ) {
    // (1) Return some HTML fragment that is used to update the DOM at client side
  } else if( $request->isXmlHttpRequest() && in_array( 'application/json', $request->getAcceptableContentTypes() ) ) {
    // (2) Return a JSON object
  } else if( in_array( 'text/html', $request->getAcceptableContentTypes() ) ) {
    // (3) Return a full HTML page from a TWIG template
  }

  // In all other cases, return a 406 error
}
Sign up to request clarification or add additional context in comments.

Comments

0

Note that $request->getRequestFormat() does not do actual format checking. It only relies on the _format request parameter (see the doc). You should use $request->getContentType() instead.

1 Comment

I see, I misunderstood the meaning of the term "request format". But at least $request->headers->get( 'accept') should do the job. $request->getContentType() is something totally different. The content type states the mime type of the body (payload) of the request. This is normally used in POST, PATCH or PUT requests. The accept header states what content type the requests expects to be the content type of the reply. In short: "content-type" determines what the request sends itsself, "accept" determines what the request expects to get back. Both can be different in the same request.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.