am05mhz
am05mhz

Reputation: 2875

What Are The Causes of Laravel 5.5 "MethodNotAllowedHttpException"

Before you down-vote me for posting another question about this error, or mark this as duplicate or anything, my question is a bit different

These are my known causes for this error:

  • form and route mismatch, eg: form uses POST, route uses GET
  • CSRF token mismatch / missing: no csrf token in meta or in form field

I have checked both of those causes:

  • have ensured form and route matches
  • have tried to disable csrf validation by commenting csrf validation middleware in app/Http/Kernel.php, but still got this error (is this correct method?)

Basically, those two are what I know, and what I found when searching here.

So my question is:

Beside those 2 causes, is there any other condition that can result in this error?

In case you want to see my code:

routes/web.php

Route::post('/export', [
    'as' => 'export.csv',
    'uses' => 'ToolsController@export'
]);

html form

    <form class="form-inline" action="{{ route('export.csv') }}" id="csv_export" method="post">
        {{ csrf_field() }}
        <input type="hidden" name="type" value="site_maps">
        <input type="hidden" name="id" value="{{ request('id') }}">
        <button type="submit" class="btn btn-primary">Export to CSV</button>
    </form>

app/Http/Controllers/ToolsController.php

namespace App\Http\Controllers;

class ToolsController extends Controller
{
    public function export(Request $request)
    {
         // some function
    }
}

Additional Detail:

There is an XSRF-TOKEN cookie set, have tried to delete it on browser, but it shows up again.

update

request header

POST /export HTTP/1.1
Host: somehost.com
Connection: keep-alive
Content-Length: 68
Pragma: no-cache
Cache-Control: no-cache
Origin: http://somehost.com
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
Save-Data: on
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://somehost.com/map/47
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,id-ID;q=0.8,id;q=0.7
Cookie: sso_token_33=--some-key--; XSRF-TOKEN=--some-token--; somehost_session=--some-cookie--

form data

_token=--some-other-token--&type=site_maps&id=47

no route grouping

update

i have a weird case, as you can see in image below, the browser is correctly send a POST request, but laravel seems to see it as GET request, is there any Apache settings that can cause this behaviour?

post vs get

route list:

+--------+----------+----------------+----------------+-------------------------------------------------+--------------+
| Domain | Method   | URI            | Name           | Action                                          | Middleware   |
+--------+----------+----------------+----------------+-------------------------------------------------+--------------+
|        | POST     | export         | export.csv     | App\Http\Controllers\ToolsController@export     | web          |
|        | GET|HEAD | map/{id}       | pages.show     | App\Http\Controllers\PagesController@show       | web          |
|        | GET|HEAD | tree           | pages.tree     | App\Http\Controllers\PagesController@tree       | web          |
+--------+----------+----------------+----------------+-------------------------------------------------+--------------+

Upvotes: 2

Views: 369

Answers (1)

Travis Britz
Travis Britz

Reputation: 5552

MethodNotAllowedHttpException is only thrown when the method doesn't match the route definition. That means all of these conditions are true:

  • The request HTTP verb (GET, POST, etc.) is not in the list of allowed methods as defined by the matched route
  • and a _method form field was not sent
  • and an X-HTTP-Method-Override header was not sent
  • and the method was not OPTIONS

Some route definitions allow multiple methods. For example, Route::get() defines GET and HEAD as acceptable.

Potential Causes

The error is actually clear (the request used the wrong method), but the cause is sometimes more subtle. Starting from most obvious to least obvious, here are common causes:

  • Sending a GET request to a route defined as Route::post()
  • Defining a DELETE, PATCH, etc. route and forgetting the _method field in an HTML form
  • Requesting the wrong route (typo, copy/paste error) - check the network tab of your developer tools and compare the Request Headers :path and :method with the URI and Method columns of php artisan route:list
  • Defining the route inside a Route::group() might have added a url prefix such as api/ or admin/ - this will be visible with route:list
  • Defining the routes in the wrong order, e.g. users/active needs to be defined before users/{user} otherwise the {user} route variable will match 'active'

If you still don't see a problem, try tinker against the path you copy from the Request Headers in the network tab of your developer tools:

$ php artisan tinker
>>> $uri = '/your/requested/path'
>>> $method = 'POST'
>>> app('router')->getRoutes()->match(app('request')->create($uri, $method))
=> Illuminate\Routing\Route {#191
 +uri: "...",
    ...

If everything still looks correct, it might be time to start examining your Apache/Nginx/IIS configurations, specifically looking for redirect/rewrite situations such as adding/removing subdomains (like www) or https.

Or, if that threw the same exception then try without the $method and carefully examine the response:

>>> app('router')->getRoutes()->match(app('request')->create($uri))

A problem with the csrf token would not cause this error. Instead, that would throw a different exception such as TokenMismatchException, or in some cases maybe an authorization error. Likewise, cookie issues should not cause an error like this.

Since this is a Laravel/Symfony exception, it should rule out an IIS/Apache/Nginx problem (unless a rewrite rule is intercepting the request). For example, IIS has some verbs disabled by default (PUT, DELETE, etc.) but instead would display an IIS 405 error page in that case.

Upvotes: 1

Related Questions