Wednesday, 19 August 2015

Symfony 2 Production Environment Issue - 405

[Note: This post is my personal experience with Symfony 2 and some strange issues I faced in production environment. Error messages were misleading to some extent. I was stuck with "405 Method Not Allowed" and  "POST request was becoming GET request"  whenever I was trying POST request but GET request was working without any hassle and it was happening only in prod env not in dev]

Here we will be talking about Symfony 2.6 (I believe it applies to other versions as well). Before proceeding, let me shed some light on what exactly happened with me and how did I solve it. I developed some API on my development machine (personal macbook pro) and everything worked perfectly fine. Taking "localhost" example and project "myTestAPI"; So when I was testing in dev environment, my URL was

http://localhost/myTestAPI/web/app_dev.php/myTestRoute
params sent : param1=value1

Above request is POST request and it worked perfectly fine with dev environment. Lets try same in prod environment on localhost itself (I hope you are familiar with environment in symfony see here)

In prod environment, api address became :

http://localhost/myTestAPI/web/myTestRoute
params sent : param1=value1

At first time, it did not work and famous issue was cache clear. I had to run clear cache command in prod environment.

php app/console cache:clear -env=prod

Here we go, it worked like charm. Now it is time to take our awesome API to server, we chose AWS ec2 free service to test our API. Simply installed LAMP stack there and making some changes in httpd.conf as asked for Symfony:


AllowOverride All (in www folder) and we are almost ready here.

Assuming host becomes "ec2-87-52-XX-YY-aws.amazon.com"

So, I tried a GET request after initial set up 

http://ec2-87-52-XX-YY-aws.amazon.com/myTestAPI/web/app_dev.php/myTestRoute  in dev environment and

http://ec2-87-52-XX-YY-aws.amazon.com/myTestAPI/web/app.php/myTestRoute  in prod environment and believe me it worked in first try. I drank a coffee of satisfaction.

But things are not that simple for programmers,  

I tried implementing my first POST api and boom, to my surprise it threw an error with http code "405 - Method not allowed" and I was wondering what exactly happened. On my localhost same code is running perfectly fine but here on ec2 server it was not and here our actual story starts :

First thing came in my mind was routing, so i cross checked routing and no doubt it was fine. I was not sure what to google even, tried few terms

"Symfony -  405 error"  (No luck here)
"Symfony - POST method becomes GET"  (even i was ashamed searching this but no luck here as well)
and few more and finally could not find any solution of this issue.


So this was time to dig down into logs and code myself. Started with Symfony logs and it says:

"request.ERROR: Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: "No route found for "GET /api/v1/user/test": Method Not Allowed (Allow: POST)" at /var/www/html/testAPI/app/cache/prod/classes.php line 2834 {"exception":"[object] (Symfony\\Component\\HttpKernel\\Exception\\MethodNotAllowedHttpException(code: 0): No route found for \"GET /api/v1/user/test\": Method Not Allowed (Allow: POST) at /var/www/html/testAPI/app/cache/prod/classes.php:2834, Symfony\\Component\\Routing\\Exception\\MethodNotAllowedException(code: 0):  at /var/www/html/testAPI/app/cache/prod/appProdUrlMatcher.php:330)"} []"

In short, Symfony was doing its work perfectly saying "you are requesting this api with method GET but routing says POST, so I can not allow you to go further."

But the question arises, we are using POST request then how on earth it is becoming GET. So I thought to check Apache logs and not to my surprise it did same what I was expecting: REDIRECT.

I could see in apache logs that whenever I am making any request in prod environment, it is redirecting it. Point to note here is that it was not about POST or GET but because of 301 redirect and "PRG" (Post Redirect Get) my next request was becoming GET automatically and hence Symfony routing was failed. 

What was causing it : Actually I was using app_dev.php in my path in dev environment and app.php in path for prod environment. There is some rewrite rule in Symfony which redirects to same path without app.php.

SO if you make any request to 

http://{host}/{application}/web/app.php/{route}

Symfony will redirect it to 

http://{host}/{application}/web/{route}

and thus request was transforming from POST to GET. So in essence, do not use app.php in path when you intent to use prod environment.

At last, I believe instead of choosing 301 for this purpose, Symfony must have chosen 307. Feel free to correct if anything you believe is misleading here,

"happy coding"







No comments:

Post a Comment