You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel删除触发405 Method Not Allowed但刷新后生效问题求助

Laravel删除操作出现405错误但记录已删除的问题

我是Laravel新手,目前遇到一个问题:每次执行删除操作时,控制台会弹出405 Method Not Allowed错误,但刷新页面后记录实际已被删除。

错误相关截图说明

  • 删除触发的错误信息:显示405 Method Not Allowed状态码,请求方式为GET,目标路径为/wastes/[记录ID]
  • 控制台日志:记录了GET请求返回405错误的详细信息

控制器代码

<?php

namespace App\Http\Controllers;

use App\Models\Waste;
use Illuminate\Http\Request;

class WasteController extends Controller
{
    public function index()
    {
        $waste = Waste::all();
        return view('wastes.index', compact('waste'));
    }

    public function create()
    {
        return view('wastes.create');
    }    

    public function store(Request $request)
    {
        // Validate the request
        $request->validate([
            'WasteID' => 'required|unique:wastes', 
            'WasteName' => 'required',
            
        ]);

        // Create
        Waste::create($request->all());

        return redirect()->route('wastes.index')->with('success', 'Waste record created successfully!');
    }

    public function show($id)
    {
        $waste = Waste::findOrFail($id);
        return view('wastes.show', compact('waste'));
    }

    public function edit($id)
    {
        $waste = Waste::findOrFail($id);
        return view('wastes.edit', compact('waste'));
    }

    public function update(Request $request, $id)
    {
        // Validate
        $request->validate([
            'WasteID' => 'required|unique:wastes,WasteID,' . $id, 
            'WasteName' => 'required',
            
        ]);

        // Update
        $waste = Waste::findOrFail($id);
        $waste->update($request->all());

        return redirect()->route('wastes.index')->with('success', 'Waste record updated successfully!');
    }

    public function destroy($id)
    {
        $waste = Waste::findOrFail($id);
        $waste->delete();

        return redirect()->route('wastes.index')->with('success', 'Waste record deleted successfully!');
    }
}

路由代码

use App\Http\Controllers\WasteController;

Route::get('/wastes', [WasteController::class, 'index'])->name('wastes.index');
Route::get('/wastes/create', [WasteController::class, 'create'])->name('wastes.create');
Route::resource('wastes', WasteController::class);
Route::delete('/wastes/delete-selected', [WasteController::class, 'deleteSelected'])->name('wastes.deleteSelected');
Route::delete('/wastes/{waste}', [WasteController::class, 'destroy'])->name('wastes.destroy');

视图代码

@extends('layouts.app')

@section('content')
    <h1>Waste Records</h1>

    @if(session('success'))
        <div class="alert alert-success">
            {{ session('success') }}
        </div>
    @endif

    <div class="mb-3">
        <a href="{{ route('wastes.create') }}" class="btn btn-primary">Create New Waste Record</a>
        <button class="btn btn-danger" onclick="deleteSelected()">Delete Selected</button>
    </div>

    <table class="table" id="wasteTable">
    <thead>
            <tr>
                <th data-sort="WasteID">Select</th>
                <th data-sort="WasteID">Waste ID</th>
                <th data-sort="WasteName">Waste Name</th>
                <th data-sort="WasteType">Waste Type</th>
                <th data-sort="TimeCollected">Time Collected</th>
                <th data-sort="MassCollected">Mass Collected</th>
                <th data-sort="AreaCollected">Area Collected</th>
                <th data-sort="DisposalLocation">Disposal Location</th>
                <th data-sort="WasteCategory">Waste Category</th>
                <th>Other Description</th>
                <th>Remarks</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            @forelse($waste as $record)
                <tr>
                    <td><input type="checkbox" name="selected[]" value="{{ $record->id }}"></td>
                    <td>{{ $record->WasteID }}</td>
                    <td contenteditable="false" data-id="{{ $record->id }}" data-field="WasteName" class="editable">{{ $record->WasteName }}</td>
                    <td>{{ $record->WasteType }}</td>
                    <td>{{ $record->TimeCollected }}</td>
                    <td>{{ $record->MassCollected }} kg</td>
                    <td>{{ $record->AreaCollected }}</td>
                    <td>{{ $record->DisposalLocation }}</td>
                    <td>{{ $record->WasteCategory }}</td>
                    <td>{{ $record->OtherDescription }}</td>
                    <td>
                        @if($record->Solid) Solid, @endif
                        @if($record->Liquid) Liquid, @endif
                        @if($record->Biodegradable) Biodegradable, @endif
                        @if($record->NonBiodegradable) Non-Biodegradable, @endif
                        @if($record->Recyclable) Recyclable, @endif
                        @if($record->Hazardous) Hazardous, @endif
                        @if($record->Corrosive) Corrosive, @endif
                        @if($record->Ignitable) Ignitable, @endif
                        @if($record->Reactive) Reactive, @endif
                        @if($record->Toxic) Toxic, @endif
                    </td>
                    <td>
                        <a href="{{ route('wastes.show', $record->id) }}" class="btn btn-info btn-sm">View</a>
                        <a href="{{ route('wastes.edit', $record->id) }}" class="btn btn-warning btn-sm">Edit</a>
                        <button class="btn btn-danger btn-sm" onclick="deleteRecord({{ $record->id }})">Delete</button>
                    </td>
                </tr>
            @empty
                <tr>
                    <td colspan="12">No waste records found.</td>
                </tr>
            @endforelse
        </tbody>
    </table>

    {{-- Scripts Area --}}
    <script src="{{ asset('jquery-3.7.1.js') }}"></script>
    <script>
         var sortOrder = {};

         
        $('table th').on('click', function() {
            var column = $(this).data('sort');
            if (!sortOrder[column]) {
                sortOrder[column] = 'asc';
            } else {
                sortOrder[column] = sortOrder[column] === 'asc' ? 'desc' : 'asc';
            }

            sortTable(column, sortOrder[column]);
        });

        
        function sortTable(column, order) {
            var rows = $('table tbody tr').get();

            rows.sort(function(a, b) {
                var keyA = $(a).children('td').eq(getColumnIndex(column)).text();
                var keyB = $(b).children('td').eq(getColumnIndex(column)).text();

                if (order === 'asc') {
                    return (keyA > keyB) ? 1 : -1;
                } else {
                    return (keyA < keyB) ? 1 : -1;
                }
            });

            $.each(rows, function(index, row) {
                $('table tbody').append(row);
            });
        }

        
        function getColumnIndex(columnName) {
            var index = -1;
            $('table th').each(function(i) {
                if ($(this).data('sort') === columnName) {
                    index = i;
                    return false;
                }
            });
            return index;
        }

        
        function sortTable(column, order) {
            var rows = $('table tbody tr').get();

            rows.sort(function(a, b) {
                var keyA = $(a).children('td').eq(getColumnIndex(column)).text();
                var keyB = $(b).children('td').eq(getColumnIndex(column)).text();

                if (order === 'asc') {
                    return (keyA > keyB) ? 1 : -1;
                } else {
                    return (keyA < keyB) ? 1 : -1;
                }
            });

            $.each(rows, function(index, row) {
                $('table tbody').append(row);
            });
        }

        
        function getColumnIndex(columnName) {
            var index = -1;
            $('table th').each(function(i) {
                if ($(this).data('sort') === columnName) {
                    index = i;
                    return false;
                }
            });
            return index;
        }

        //!!
        function deleteSelected() {
            var selectedIds = $('input[name="selected[]"]:checked').map(function(){
                return $(this).val();
            }).get();

            if (selectedIds.length === 0) {
                alert('Please select at least one record to delete.');
                return;
            }

            if (confirm('Are you sure you want to delete selected records?')) {
                $.ajax({
                    url: '{{ route('wastes.deleteSelected') }}',
                    type: 'DELETE',
                    data: {
                        "_token": "{{ csrf_token() }}",
                        "selectedIds": selectedIds
                    },
                    success: function(response) {
                        alert(response.message);
                        location.reload();
                    },
                    error: function(xhr) {
                        alert('Error deleting selected records.');
                    }
                });
            }
        }

        //!!
        function deleteRecord(WasteID) {
            if (confirm('Are you sure you want to delete this record?')) {
                $.ajax({
                    url: '/wastes/' + WasteID,
                    type: 'DELETE',
                    data: {
                        "_token": "{{ csrf_token() }}",
                    },
                    success: function(response) {
                        alert(response.message);
                        location.reload();
                    },
                    error: function(xhr) {
                        alert('Error deleting the record.');
                    }
                });
            }
        }
    </script>
    <script>
        $(document).ready( function () {
            $('#wasteTable').DataTable();
    });
    </script>
@endsection

问题原因及解决办法

1. 路由重复定义导致冲突

Route::resource('wastes', WasteController::class)已经自动生成了所有RESTful路由,包括index、create、destroy等。你额外手动添加的Route::get('/wastes', ...)、Route::get('/wastes/create', ...)和Route::delete('/wastes/{waste}', ...)都是重复路由,而且手动路由在resource路由之后,会导致路由匹配逻辑混乱。

解决:
修改路由文件,只保留必要的路由:

use App\Http\Controllers\WasteController;

Route::resource('wastes', WasteController::class);
Route::delete('/wastes/delete-selected', [WasteController::class, 'deleteSelected'])->name('wastes.deleteSelected');

2. 控制器返回值不符合AJAX请求预期

你的destroy方法返回的是页面重定向,这是给普通表单提交用的。但前端用的是AJAX请求,AJAX期望接收JSON响应,而不是重定向指令。当AJAX收到重定向响应后,会自动发起GET请求到重定向的URL,这个GET请求不符合destroy路由要求的DELETE方法,因此触发405错误。

解决:
修改控制器的destroy方法,添加缺失的deleteSelected方法,返回JSON响应:

public function destroy($id)
{
    $waste = Waste::findOrFail($id);
    $waste->delete();

    return response()->json(['message' => 'Waste record deleted successfully!']);
}

public function deleteSelected(Request $request)
{
    Waste::whereIn('id', $request->selectedIds)->delete();
    return response()->json(['message' => 'Selected records deleted successfully!']);
}

3. 前端AJAX URL硬编码优化(可选)

单个删除的AJAX中,硬编码URL不够可靠,改用路由生成方式更稳妥:

function deleteRecord(id) {
    if (confirm('Are you sure you want to delete this record?')) {
        $.ajax({
            url: '{{ route('wastes.destroy', ':id') }}'.replace(':id', id),
            type: 'DELETE',
            data: {
                "_token": "{{ csrf_token() }}",
            },
            success: function(response) {
                alert(response.message);
                location.reload();
            },
            error: function(xhr) {
                alert('Error deleting the record.');
            }
        });
    }
}

内容的提问来源于stack exchange,提问作者AverageWeebo101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 12:44:55