将文件从 VueJS 应用程序上传到 Laravel 中的 API

Upload file from VueJS app to API in Laravel

我正在尝试将文件 (Excel sheet) 从使用 VueJS 构建的 front-end 应用程序上传到使用 Laravel 5.5 构建的 API .我有一些表单请求验证对我说 The file field is required。所以文件根本没有上传到我的 API。

VueJS 文件上传:

onFileChange(e) {
  let files = e.target.files || e.dataTransfer.files;

  if (files.length <= 0) {
    return;
  }

  this.upload(files[0]);
},
upload(file) {
  this.form.file = file;

  this.form.put('courses/import')
    .then((response) => {
      alert('Your upload has been started. This can take some time.');
    })
    .catch((response) => {
      alert('Something went wrong with your upload.');
    });
}

this.form 是从 this project but the data() method returns a FormData 对象而不是对象复制的表单 class。

data()方法:

data() {
    let data = new FormData();

    for (let property in this.originalData) {
        data.append(property, this[property]);
    }

    return data;
}

路线:

表单请求规则:

public function rules()
{
    return [
        'file' => 'required',
    ];
}

如果我查看 Chrome DevTools 中的“网络”选项卡,似乎请求已正确发送:(image after click).

我尝试了很多方法,比如将 excel 作为 base64 发送到 api。但后来我无法正确解码。所以现在我正在尝试这个,但我无法解决问题。

编辑(控制器功能)

public function update(ImportRequest $request, CoursesImport $file)
{
    $courses = $file->handleImport();

    dispatch(new StartCourseUploading($courses, currentUser()));

    $file->delete();

    return ok();
}

您的状态为 422,根据您的 回复 class,我希望您了解此含义,因为 验证失败 的规则。

在laravel中,PUT方法不接受文件上传,因此您需要将PUT方法改为POST。

this.form.post('courses/import')
    .then((response) => {
      alert('Your upload has been started. This can take some time.');
    })
    .catch((response) => {
      alert('Something went wrong with your upload.');
    });

别忘了更新 laravel 的路线。

其他注意事项:

  1. 确保添加了 属性 类以下代码

    data: {
        form: new Form({
            file:null
        })
    },
    
  2. 检查浏览器请求天气发送表单数据是否正确,我添加了示例屏幕截图

我的代码示例

class Errors {
  /**
   * Create a new Errors instance.
   */
  constructor() {
    this.errors = {};
  }


  /**
   * Determine if an errors exists for the given field.
   *
   * @param {string} field
   */
  has(field) {
    return this.errors.hasOwnProperty(field);
  }


  /**
   * Determine if we have any errors.
   */
  any() {
    return Object.keys(this.errors).length > 0;
  }


  /**
   * Retrieve the error message for a field.
   *
   * @param {string} field
   */
  get(field) {
    if (this.errors[field]) {
      return this.errors[field][0];
    }
  }


  /**
   * Record the new errors.
   *
   * @param {object} errors
   */
  record(errors) {
    this.errors = errors;
  }


  /**
   * Clear one or all error fields.
   *
   * @param {string|null} field
   */
  clear(field) {
    if (field) {
      delete this.errors[field];

      return;
    }

    this.errors = {};
  }
}


class Form {
  /**
   * Create a new Form instance.
   *
   * @param {object} data
   */
  constructor(data) {
    this.originalData = data;

    for (let field in data) {
      this[field] = data[field];
    }

    this.errors = new Errors();
  }


  /**
   * Fetch all relevant data for the form.
   */
  data() {
    let data = new FormData();

    for (let property in this.originalData) {
      data.append(property, this[property]);
    }

    return data;
  }


  /**
   * Reset the form fields.
   */
  reset() {
    for (let field in this.originalData) {
      this[field] = '';
    }

    this.errors.clear();
  }


  /**
   * Send a POST request to the given URL.
   * .
   * @param {string} url
   */
  post(url) {
    return this.submit('post', url);
  }


  /**
   * Send a PUT request to the given URL.
   * .
   * @param {string} url
   */
  put(url) {
    return this.submit('put', url);
  }


  /**
   * Send a PATCH request to the given URL.
   * .
   * @param {string} url
   */
  patch(url) {
    return this.submit('patch', url);
  }


  /**
   * Send a DELETE request to the given URL.
   * .
   * @param {string} url
   */
  delete(url) {
    return this.submit('delete', url);
  }


  /**
   * Submit the form.
   *
   * @param {string} requestType
   * @param {string} url
   */
  submit(requestType, url) {
    return new Promise((resolve, reject) => {
      axios[requestType](url, this.data())
        .then(response => {
          this.onSuccess(response.data);

          resolve(response.data);
        })
        .catch(error => {
          this.onFail(error.response.data);

          reject(error.response.data);
        });
    });
  }


  /**
   * Handle a successful form submission.
   *
   * @param {object} data
   */
  onSuccess(data) {
    alert(data.message); // temporary

    this.reset();
  }


  /**
   * Handle a failed form submission.
   *
   * @param {object} errors
   */
  onFail(errors) {
    this.errors.record(errors);
  }
}


var app = new Vue({
  el: '#app',

  data: {
    form: new Form({
      file: ''
    })
  },
  methods: {
    onSubmit() {
      this.form.post('/projects')
        .then(response => alert('Wahoo!'));
    },
    onFileChange(e) {
      let files = e.target.files || e.dataTransfer.files;

      if (files.length <= 0) {
        return;
      }

      this.upload(files[0]);
    },
    upload(file) {
      this.form.file = file;

      this.form.post('courses/import')
        .then((response) => {
          alert('Your upload has been started. This can take some time.');
        })
        .catch((response) => {
          alert('Something went wrong with your upload.');
        });
    }
  }
});
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.2.3/css/bulma.css">
  <style>
    body {
      padding-top: 40px;
    }
  </style>
</head>

<body>
  <div id="app" class="container">


    <form method="POST" action="/projects" @submit.prevent="onSubmit" @keydown="form.errors.clear($event.target.name)">

      <input type="file" name="image" @change="onFileChange">
        
      <div class="control">
        <button class="button is-primary" :disabled="form.errors.any()">Create</button>
      </div>
    </form>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.js"></script>
  <script src="https://unpkg.com/vue@2.1.6/dist/vue.js"></script>

</body>

</html>

相关链接

https://github.com/laravel/framework/issues/17560

如果您将数据存储在关联数组中,例如数据:

var formData = new FormData();
Object.keys(data).forEach(function(key, index){
    if(Array.isArray(data[key])){
        formData.append(key + '[]', data[key]);
    } else {
        formData.append(key, data[key]);
    }
});
formData.append('file', document.getElementById('file_id').files[0]);
axios.post('path', formData).then( res => {
    console.log(res);
}).catch(res => {
    console.log(res);
});