Laravel 5 使用 AJAX 时文件上传不起作用

Laravel 5 file upload not working when using AJAX

我以前在处理 Laravel 时从未遇到过这个问题。

我有一个表格,可以插入产品详细信息,其中还有一个图像字段。

以下是我如何创建用于插入产品详细信息的视图:

{!! Form::open(['url' => '/admin/products', 'autocomplete' => 'off', 'id' => 'formAddProduct', 'files' => true]) !!}
    <div class="errors"></div>

    @include('admin.products.form', ['submitButtonText' => 'Add Product', 'submitButtonId' => 'btnAddProduct'])
{!! Form::close() !!}

form.blade.php:

<div class="form-group">
    {!! Form::label('code', 'Code') !!}
    {!! Form::text('code', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('name', 'Name:') !!}
    {!! Form::text('name', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('category_id', 'Category:') !!}
    {!! Form::select('category_id', $categories, null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('short_description', 'Short Description:') !!}
    {!! Form::text('short_description', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('description', 'Long Description:') !!}
    {!! Form::text('description', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('price', 'Price:') !!}
    {!! Form::text('price', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('discount_price', 'Discount Price:') !!}
    {!! Form::text('discount_price', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('display', 'Display Status:') !!}
    {!! Form::select('display', ['Enabled' => 'Enabled', 'Disabled' => 'Disabled'], null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('image_file', 'Image:') !!}
    {!! Form::file('image_file', ['id' => 'image_file', 'class' => 'form-control input-sm']) !!}
</div>

<div class="form-group">
    {!! Form::submit($submitButtonText, ['class' => 'btn btn-primary btn-block', 'id' => $submitButtonId]) !!}
</div>

控制器方法:

public function store( Request $request ) {
    $this->validate($request, [
        'code'              => 'required|alpha_dash|unique:products',
        'name'              => 'required',
        'category_id'       => 'required|integer',
        'short_description' => 'string',
        'description'       => 'required',
        'price'             => 'required|regex:/^\d*(\.\d{2})?$/',
        'discount_price'    => 'regex:/^\d*(\.\d{2})?$/',
        'display'           => 'required|in:Enabled,Disabled',
        'image_file'        => 'mimes:jpg'
    ]);

    if ( $request->ajax() ) {
        Product::create( $request->all() );

        if ( $request->file( 'image_file' ) ) {

            $filename = Safeurl::make( $request->get( 'code' ) );
            $image = Image::make( $request->file( 'image_file' ) );
            $path = public_path( 'images/uploads/products/' );

            $image->resize( 450, 450 )->save( $path.$filename.'.jpg', 100 );
        } else {
            return response(['msg' => 'No File']);
        }
        return response(['status' => 'success', 'msg' => 'The product has been added successfully.']);
    }
        return response(['status' => 'failed', 'msg' => 'The product could not be added successfully.']);
    }

和 ajax:

$('#btnAddProduct').on('click', function() {
    var inputData = $('#formAddProduct').serialize();

    $.ajax({
        url: '{{ url('/admin/products') }}',
        type: 'POST',
        data: inputData,
        success: function( message ) {
            alert( message.msg );
            if ( message.status === 'success' ) {
                toastr.success('Product added successfully.');
                toastr.options.closeButton = true;
                toastr.options.showMethod = "slideDown";
                toastr.options.hideMethod = "slideUp";

                $('input').val( '' );
                $('select').val( '' );
            }
        },
        error: function( data ) {
            if ( data.status === 422 ) {
                var errors = data.responseJSON;
                var errorsHtml = '<div class="alert alert-danger"><ul>';
                errorsHtml += '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>';
                $.each( errors, function( key, value ) {
                    errorsHtml += '<li>' + value[0] + '</li>'; //showing only the first error.
                });
                errorsHtml += '</ul></div>';

                $( '.errors' ).html( errorsHtml );
            }
        }
    });

    return false;
});

我得到的错误是No file

当我执行 var_dump( $request->file( 'image_file' ) ); 时,我在 chrome

的响应选项卡中得到 null

当我执行 var_dump( Input::file( 'image_file' ) ); 时,我在 chrome

的响应选项卡中得到 null

我哪里弄错了?请帮助我。谢谢。

P.S.: 我已经使用 Intervention 作为我的图片上传功能。

serialize() 方法不发送文件信息供远程处理程序处理。另一种方法是使用 FormData。 请参阅此 link 示例:http://portfolio.planetjon.ca/2014/01/26/submit-file-input-via-ajax-jquery-easy-way/

注意:在 jQuery ajax 请求中将 processData 和 contentType 设置为 false 很重要,否则在 jQuery 尝试处理它时会导致错误。

您应该在 ajax 调用

中添加 data: formData,async: false,

所以你的 ajax 将是

$("form[name='yourformname']").submit(function(e) {//If you use form submit then have your form name here
//$('#btnAddProduct').on('click', function() {
var inputData = new FormData($(this)[0]);
//var inputData = $('#formAddProduct').serialize(); not matter :p
  e.preventDefault();
$.ajax({
    url: '{{ url('/admin/products') }}',
    type: 'POST',
    data: inputData,
    async: false,
    success: function( message ) {
        alert( message.msg );
        if ( message.status === 'success' ) {
            toastr.success('Product added successfully.');
            toastr.options.closeButton = true;
            toastr.options.showMethod = "slideDown";
            toastr.options.hideMethod = "slideUp";

            $('input').val( '' );
            $('select').val( '' );
        }
    },
    error: function( data ) {
        if ( data.status === 422 ) {
            var errors = data.responseJSON;
            var errorsHtml = '<div class="alert alert-danger"><ul>';
            errorsHtml += '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>';
            $.each( errors, function( key, value ) {
                errorsHtml += '<li>' + value[0] + '</li>'; //showing only the first error.
            });
            errorsHtml += '</ul></div>';

            $( '.errors' ).html( errorsHtml );
        }
    }
});

return false;
});

更新:

  1. 在 ajax 通话中转 async:true

  2. 在你的 Laravel 验证器规则中加入这个 image_file' => 'mimes:jpeg,jpg,JPG'

在发出包含包装在 formData 对象中的文件的 Ajax 请求之前,您需要了解一些陷阱和技巧。

  1. 确保设置 contentType: falseprocessData: false
  2. 如果您只是在 formData 上附加文件,请确保您像这样访问文件数据

//This function collects all form fields to be appended 
//to a formData object
function collectFormData($form){
    var formdata  =  new FormData(), value, fieldId,$field ;
var formFields = ['title','summary','categories','tags','screenshot','flowchart'];
                
    $form.find('input , select , textarea').each(function(){
      $field  =  $(this);
      fieldId = $field .attr('id')
     //check whether this field is needed
        if($.inArray(fieldId, formFields) !== -1 ){
            switch (fieldId) {
            //access the file content of the file input
                    case 'screenshot':
                    value = $field[0].files[0];
                    break;
                     case 'flowchart':
                    value = $field[0].files[0];
                    break;
                default:
                value  =  $field.val();
                break;
            }//end switch
            formdata.append(fieldId, value)
        }//end if
    });
    return formdata;
}

function submitFormData(){
  $('.submit-btn').on('click', function(e){
    e.preventDefault();
var $thisBtn  =  $(this);
var $form  =  $thisBtn.closest('form');

var formdata  =  collectFormData($form);

//add token for laravel projects
$.ajaxSetup({'headers': {'X-CSRF-TOKEN':$form.find('input[name="_token"]').val()}});


//prepare an ajax request to send form details
$.ajax({
    url: $form.attr('action'),
        method: "post",
        processData: false, //Do not allow proccessing of the data
        dataType: "json", //you can change this property
        data: formdata, //this is our formData object being passed here
        async: false,
       cache: false,
       contentType: false, //very important for sending files

        success: function(data) {
            console.log(data)
        }, error:function(data){
            console.log(data)
        }
});//end ajax request

return false;
  });

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="path/to/your/backendscript" id="uploadForm" method="post">

            <input type="text" name="title" id="title" >

            <textarea name="summary" id="summary" cols="30" rows="10"></textarea>

            <select name="categories[]" multiple id="categories">
                <option>Web Development</option>
                <option>Java Programming</option>
                <option>PHP programming</option>
            </select>


            <select name="tags[]" multiple id="tags">
                <option>AJAX</option>
                <option >Swing Components</option>
                <option>Laravel</option>
            </select>

            <input type="file" name="screenshot" id="screenshot">
            <input type="file" name="flowchart" id="flowchart">
<button class="submit-btn" type="submit">Submit</button>
        </form>

这是非常适合我的解决方案。干杯!