Vueで署名済みS3 URIにファイルデータをPOSTする方法

2020-03-30 vue.js amazon-s3 axios vuetify.js

Railsバックエンドを備えたVueアプリを作成しています。私は次のようなワークフローを提案するいくつかの記事をオンラインでフォローしています。

  1. Rails APIに署名済みのS3 URLを生成させる
  2. VueアプリのAPIリクエストで取得したもの
  3. そのリクエストからのデータを使用して、実際の画像を直接S3にPOSTします

最初の2つのステップは正常に機能していますが、タイプが「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>

このリクエストは次のエラーで失敗します

<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>

元のformDataを見ると、filedataが空のようです。また、リクエストのサイズは十分に大きくないため、ファイルがないと想定しています。このリクエストのファイルをシリアル化するための追加の作業はありますか?

ありがとう

Answers

問題は、 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(...)
}

Related