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

Laravel图片上传POST请求返回405错误,路由与方法已存在

Laravel拖拽上传图片返回405 Method Not Allowed问题排查与解决

我是Laravel开发新手,正在构建支持表单和拖拽上传图片的小型应用。尝试通过POST路由及Controller的store方法上传图片时,应用始终返回ERROR 405 - Method Not Allowed,相关代码如下:

相关代码

web.php路由配置

Route::resource('colaboradores', ColaboradoresController::class, ['only' => ['index', 'store', 'update', 'destroy']]);

拖拽区域表单代码

<form enctype="multipart/form-data" action="{{ route('administrativo.secoes.colaboradores.store') }}" id="image-upload-form">
    <input type="file" name="file" id="image-input" class="dropzone-input" onchange="get_images(this)" multiple hidden>
    <div class="drop-zone" id="image-dropzone" ondragover="dragOverHandler(event);" ondrop="dropHandler(event);">
        <div class="inner-elements">
            <label for="image-input">
                <h3>Drag your pictures here</h3>
                <span class="note needsclick">Or click here to manually select them.</span>
            </label>
        </div>
    </div>
</form>

AJAX请求的JavaScript代码

function dragOverHandler(ev) {
    document.getElementById("image-dropzone").style.border = "3px solid #00f752";
    ev.preventDefault();
}

function dropHandler(ev) {
    document.getElementById("image-dropzone").style.border = "3px dashed #0087f7";
    ev.preventDefault();
    if (ev.dataTransfer.items) {
        [...ev.dataTransfer.items].forEach((item, i) => {
            if (item.type.includes("image")) {
                const file = item.getAsFile();
                upload_image(file);
            }
        });
    }
}

function get_images() {
    var total_images = document.getElementById("image-input").files.length;
    if (total_images > 0) {
        for (var index = 0; index < total_imagens; index++) {
            var file = document.getElementById("image-input").files[index];
            upload_image(file);
        }
    }
}

function upload_image(file) {
    var form_data = new FormData();
    form_data.append("file", file);
    form_data.append("test", "test");

    $.ajaxSetup({
        headers: {
            "X-CSRF-TOKEN": $("meta[name='csrf-token']").attr("content")
        }
    });

    $.ajax({
        type: "PUT",
        url: `${window.location.pathname}/store/`,
        data: form_data,
        cache: false,
        contentType: false,
        processData: false,
        success: function (data) {
            console.log(data);
        },
        error: function (data) {
            console.log(data);
        }
    });
}

ColaboradoresController.php代码

<?php

namespace App\Http\Controllers\Administrativo;

use App\Http\Controllers\Controller;
use App\Models\SectionCollaborators;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;

class ColaboradoresController extends Controller
{
    public function index()
    {
      //
    }

    public function create()
    {
      //
    }

    public function store(Request $request)
    {
        try {
            $novo_nome = self::upload_imagem($request);
            return response()->json(["imagem" => "$novo_nome", "mensagem" => "Imagem salva com sucesso."], 200);
        } catch (Exception $e) {
            return response()->json(["mensagem" => "Ocorreu um erro ao salvar a imagem. Tente novamente."], 500);
        }
    }

    private function upload_imagem(Request $request)
    {
        if ($request->hasFile('file') && $request->file('file')->isValid()) {
            $request->validate([
                'file' => 'required|image|mimes:jpeg,png,jpg,webm,svg|max:2048',
            ]);

            $img = $request->file;
            $novo_nome = Storage::disk('local')->put('public/img/colaboradores/cards', $img, 'public');

            return basename($novo_nome);
        }
    }

    public function update(Request $request)
    {
       //
    }

    private function update_text($object, $nome, $valor)
    {
       //
    }

    public function destroy(Request $request)
    {
       //
    }

    public function setId(int $value)
    {
        //
    }

    public function getId()
    {
        //
    }
 }

核心错误原因及修复方案

1. 请求方法不匹配

Laravel资源路由的store方法默认只接受POST请求,但你的AJAX代码里用了PUT方法,这直接导致405错误。

修复:将AJAX的请求类型改为POST:

$.ajax({
    type: "POST", // 替换原有的"PUT"
    // ...其他参数
});

2. 请求URL错误

你手动拼接的URL ${window.location.pathname}/store/ 大概率和路由定义的实际地址不匹配,而表单里已经通过route('administrativo.secoes.colaboradores.store')生成了正确的URL,应该复用这个地址。

修复:

  • 先给表单添加一个存储路由URL的属性:
<form enctype="multipart/form-data" action="{{ route('administrativo.secoes.colaboradores.store') }}" id="image-upload-form" data-store-url="{{ route('administrativo.secoes.colaboradores.store') }}">
  • 然后在JS中获取这个正确的URL:
function upload_image(file) {
    // 获取表单中存储的正确路由URL
    const storeUrl = document.getElementById('image-upload-form').dataset.storeUrl;
    
    var form_data = new FormData();
    form_data.append("file", file);
    form_data.append("test", "test");

    $.ajaxSetup({
        headers: {
            "X-CSRF-TOKEN": $("meta[name='csrf-token']").attr("content")
        }
    });

    $.ajax({
        type: "POST",
        url: storeUrl, // 使用正确的路由URL
        data: form_data,
        cache: false,
        contentType: false,
        processData: false,
        success: function (data) {
            console.log(data);
        },
        error: function (data) {
            console.log(data);
        }
    });
}

3. JavaScript变量拼写错误

get_images函数中,循环条件里的total_imagens是拼写错误,应该是total_images,否则手动选择图片时循环不会执行。

修复:

function get_images() {
    var total_images = document.getElementById("image-input").files.length;
    if (total_images > 0) {
        // 把total_imagens改为total_images
        for (var index = 0; index < total_images; index++) {
            var file = document.getElementById("image-input").files[index];
            upload_image(file);
        }
    }
}

4. 验证路由命名是否正确

确保你的路由分组配置正确,生成的路由名称和route('administrativo.secoes.colaboradores.store')一致。如果路由是嵌套在分组里,需要这样配置:

Route::prefix('administrativo/secoes')->name('administrativo.secoes.')->group(function () {
    Route::resource('colaboradores', ColaboradoresController::class, ['only' => ['index', 'store', 'update', 'destroy']]);
});

可以通过执行php artisan route:list命令查看所有路由的详细信息,确认store路由的请求方法是POST,名称和URL正确。

额外建议

  • 上传文件时,确保upload_imagem方法中处理了文件验证失败的情况,比如添加返回值或抛出异常,避免出现静默错误。
  • 测试时可以在浏览器控制台查看AJAX请求的具体URL和方法,确认和路由定义一致。

内容的提问来源于stack exchange,提问作者Gian Luca Oliveira

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:30:58