Я не могу отправить файл через запрос ajax PUT, используя Laravel

#ajax #laravel #file #controller #request

#ajax #laravel #файл #контроллер #запрос

Вопрос:

У меня есть форма с вводом типа file hidden. Тег изображения работает как триггер для выбора самого файла, с помощью js для его запуска (это работает), но я хочу автоматически отправлять запрос PUT при выборе изображения вместо того, чтобы нажимать кнопку отправки в форме каждый раз, когда изображение изменяется в поле ввода. Для этого я использую ajax, но на конечной точке контроллера, которая обрабатывает запрос, у меня, похоже, нет никакого файла. Однако, если я добавляю другие поля, такие как текстовые, они, похоже, передаются в контроллер через запрос просто отлично.

Мой маршрут:

 Route::put('/coins/image/{key}', [CoinController::class, 'image'])->name("coins.image");
 

Мой контроллер (пока нет фактического кода обновления изображения; только то, что я делаю для проверки файла):

 public function image(int $key)
{
    dump(request()->file('file'));
    dump(request()->file);
    dump(request());
}
 

Мой HTML и JS в следующем фрагменте:

 function promptImageForUpload(elemId)
{
    $('#'   elemId).click();
}

function uploadImage(event, imgId, key)
{
    event.preventDefault();
    var inputElem = event.target;
    var imageFile = inputElem.files[0];
    var imgElem = $('#'   imgId);
    var form = $(inputElem).parent();
    var formData = new FormData(form[0]);
    formData.append('file', imageFile);
    $.ajax({
        url: "/coins/image/"   key,
        type: "PUT",
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
        },
        data: formData,
        enctype: 'multipart/form-data',
        processData: false,
        contentType: false,
        success: function(response) {
            var reader = new FileReader();
            reader.onload = function(e) {
                imgElem.attr("src", e.target.result);
            };
            reader.readAsDataURL(imageFile); // convert to base64 string
        }
    });
} 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="card-body">
   <form data-key="0" id="coin-header-0_form" method="POST" action="#" enctype="multipart/form-data">
      <input type="file" name="file" id="coin-header-0_file" style="z-index:-1; width: 100%; height: 100%; display: none;" onchange="uploadImage(event, 'coin-header-0_preview', 0)">
      <input type="hidden" name="_method" value="PUT">
      <meta name="csrf-token" content="7c3s2NmosdK9qzrS10xGAB0rYXw5g41azRjcmPQC">
      <img src="http://snapbuilder.com/code_snippet_generator/image_placeholder_generator/60x40/007730/DDDDDD/this pict" width="50px" height="50px" alt="icon" id="coin-header-0_preview" onclick="promptImageForUpload('coin-header-0_file');">
   </form>
</div> 

На данный момент я принудительно обновляю предварительный просмотр изображения при успешном выполнении ajax вместо того, чтобы извлекать его из обновленного объекта после успешного обновления, чтобы избежать второго запроса.

У меня установлен метод PUT для подмены в запросе ajax, а токен xsrf также задает заголовки. Для Enctype также задано значение multipart / form-data для файлов. Я понятия не имею, почему я не вижу загруженный файл нигде в запросе.

Используя Laravel Framework 8.25.0, jquery 3.5.1.

Пожалуйста, дайте мне знать, если кому-нибудь понадобится дополнительная информация. Я не смог найти никакого решения ни в одной записи stackoverflow или где-либо еще, что касается этой темы. Любая помощь очень ценится, так как я действительно не знаю, как еще взглянуть на это с точки зрения подхода к отладке.

Ответ №1:

HTML-формы не поддерживают PUT PATCH или DELETE действия. Итак, при определении PUT PATCH DELETE маршрутов or, которые вызываются из HTML-формы, вам нужно будет добавить скрытое _method поле в форму. Значение, отправленное с _method полем, будет использоваться в качестве метода HTTP-запроса:

 <form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
 

Вы можете использовать помощник method_field для генерации ввода _method:

 {{ method_field('PUT') }}
 

Таким же образом эта проверка может также повлиять на формы ajax. Затем в вашей форме переключитесь на метод POST и установите параметр PUT, чтобы он работал.

Комментарии:

1. Заранее спасибо. После большого пересмотра кода я заметил, что пропустил метод в форме GET. Я знаю, что формы не поддерживают другие методы, кроме GET и POST, но я подумал, что параметр «type: PUT» в запросе ajax будет подделывать метод, подобный Laravel @method (‘PUT’). Я предполагаю, что это не делает то, для чего я думал, что это предназначено, я добавил новое скрытое поле в форму, как вы предложили, но отправленный файл по-прежнему остается пустым. Обновляю вопрос, чтобы отразить ваши предложения, которые уже есть, и с выводом для дампа запроса.