如何使用 Vue 将文件数据 POST 到预签名的 S3 URI?

bo-*_*-oz 2 amazon-s3 vue.js axios vuetify.js

我正在构建一个带有 Rails 后端的 Vue 应用程序。我正在关注一些在线文章,这些文章建议了一个工作流程,其中我:

  1. 让我的 Rails API 生成预签名的 S3 url
  2. 我通过 Vue 应用程序中的 API 请求获得的
  3. 我使用该请求中的数据将实际图像直接发布到 S3

前两个步骤工作正常,但我很难理解如何将文件数据包含在类型为“multipart/form-data”的请求中。

我的代码如下,我使用vuetify作为组件库:

<template>
    <v-form>
      <v-file-input v-model="file" label="File input"></v-file-input>
      <v-btn class="mt-2" block bottom color="primary" @click="submit">Opslaan</v-btn>
    </v-form>
</template>

<script>
import { axios_request } from '../_helpers';

export default {
  name:'AccountImageForm',
  data: () => ({
    file: {}
  }),
  methods: {
    filesChange(event) {
      this.file = event.target.files[0]
    },
    submit() {
      axios_request('/api/v1/images/upload_url')
        .then(
          response => {
            // this response contains the pre-signed info
            var data = {
              ...response.url_fields,
              file: this.file
            }
            var headers = { 'Content-Type': 'multipart/form-data' }
            axios_request(response.url, 'POST', data, headers)
              .then(
              response => {
                console.log(response)
              }
            )
          }
        )
    },
  }
}
</script>
Run Code Online (Sandbox Code Playgroud)

此请求失败并出现以下错误

<Error>
  <Code>MalformedPOSTRequest</Code>
  <Message>The body of your POST request is not well-formed multipart/form-data.</Message>
  <RequestId>x</RequestId>
  <HostId>xx</HostId>
</Error>
Run Code Online (Sandbox Code Playgroud)

当我查看原始的 formData 时,似乎 filedata 是空的。另外,请求的大小不够大,所以我的假设是文件丢失。是否需要一些额外的工作来序列化此请求的文件?

谢谢

Phi*_*hil 5

问题是您正在尝试发布,multipart/form-data但发送的是 Axios 可能只是字符串化的 JS 对象文字。

您需要做的是创建一个FormData实例。

例如

response => {
  // convert your url_fields into a FormData instance
  const data = Object.entries(response.url_fields).reduce((fd, [ key, val ]) =>
      (fd.append(key, val), fd), new FormData())

  // now add the file
  data.append('file', this.file)

  axios_request(response.url, 'POST', data)
    .then(...)
}
Run Code Online (Sandbox Code Playgroud)