Laravel 5.5“ MethodNotAllowedHttpException”的原因是什么

时间:2018-11-14 08:57:20

标签: php laravel

<罢工> 在您否决我是否要发布有关此错误的另一个问题,或将其标记为重复或其他内容之前,我的问题有所不同

这些是导致此错误的我的已知原因:

  • 表单和路由不匹配,例如:表单使用POST,路由使用GET
  • CSRF令牌不匹配/丢失:元数据或表单字段中没有csrf令牌

我已经检查了这两个原因:

  • 确保形式和路线匹配
  • 尝试通过注释csrf中的csrf验证中间件来禁用app/Http/Kernel.php验证,但仍然收到此错误(这是正确的方法吗?)

基本上,这两个是我所知道的,也是我在这里搜索时发现的。

所以我的问题是:

除了这两个原因外,还有其他情况会导致此错误吗?

如果您想查看我的代码:

routes / web.php

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

html表单

    <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
    }
}

其他详细信息:

有一个XSRF-TOKEN cookie集,试图在浏览器上将其删除,但它再次出现。

更新

请求标头

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--

表单数据

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

<罢工> 没有路线分组

更新

我有一个奇怪的情况,如下图所示,浏览器正确发送了POST请求,但是laravel似乎将其视为GET请求, 是否有任何Apache设置会导致此行为?

post vs get

路线列表:

+--------+----------+----------------+----------------+-------------------------------------------------+--------------+
| 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          |
+--------+----------+----------------+----------------+-------------------------------------------------+--------------+

1 个答案:

答案 0 :(得分:1)

当方法与路线定义不匹配时,将仅 抛出

MethodNotAllowedHttpException。这意味着所有这些条件都是正确的:

  • 请求的HTTP动词(GET,POST等)不在匹配路由定义的允许方法列表中
  • 没有发送_method表单字段
  • 没有发送X-HTTP-Method-Override标头
  • 该方法不是OPTIONS

某些路由定义允许多种方法。例如,Route::get()将GET和HEAD定义为可接受。

潜在原因

该错误实际上很明显(请求使用了错误的方法),但是原因有时更微妙。从最明显到最不明显,这是常见原因:

  • 将GET请求发送到定义为Route::post()的路由
  • 定义DELETE,PATCH等路线,并忘记HTML表单中的_method字段
  • 请求错误的路线(输入错误,复制/粘贴错误)-检查开发人员工具的网络标签,并将请求标头 :path:method与URI进行比较和php artisan route:list
  • 的“方法”列
  • Route::group()内定义路由可能已添加了URL前缀,例如api/admin/-这将在route:list上可见
  • 以错误的顺序定义路线,例如需要在users/active之前定义users/{user},否则{user}路由变量将与'active'匹配

如果仍然没有发现问题,请尝试修改开发人员工具的“网络”标签中“请求标头”中复制的路径

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

如果所有 still 看起来都正确,则可能是时候开始检查Apache / Nginx / IIS配置了,特别是查找重定向/重写情况,例如添加/删除子域(如www)或https

或者,如果抛出相同的异常,则尝试不使用$方法并仔细检查响应:

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

csrf令牌问题将不会引起此错误。相反,这将引发不同的异常,例如TokenMismatchException,或者在某些情况下可能会出现授权错误。同样,Cookie问题不应导致此类错误。

由于这是Laravel / Symfony异常,因此应该排除IIS / Apache / Nginx问题(除非重写规则拦截了请求)。例如,IIS默认情况下禁用了一些动词(PUT,DELETE等),但在这种情况下,它将显示IIS 405错误页面。