首页 > 解决方案 > 如何使用预签名的 URL 将图像上传到亚马逊 aws S3

问题描述

嗨,当我尝试使用我的 vue 应用程序中的预签名 url 将图像上传到我的亚马逊 aws 存储桶时,我收到 400 错误请求错误。我已经成功生成了一个预签名的 url,但我无法使用它将图像发布到我的存储桶中。

获取预签名网址的路线

const express = require('express')
const router = new express.Router()
const requireAuth = require('../middleware/requireAuth')

router.use(requireAuth)

const v4 = require('uuid')

const AWS = require('aws-sdk')
const s3 = new AWS.S3({
    region: process.env.BUCKET_REGION,
    accessKeyId: process.env.ACCESS_KEY_ID,
    secretAccessKey: process.env.SECRET_ACCESS_KEY
})

router.get('/upload', async (req, res) => {
    const key = `${req.user._id}/${v4()}.jpeg`

    s3.getSignedUrl('putObject', {
        Bucket: 'my-post-app-bucket',
        ContentType: 'image/jpeg',
        Key: key
    }, (err, url) => res.send({ key, url }))
})

module.exports = router

Vue客户端

<template>
  <form @submit.prevent="handleSubmit">
    <input type="file" @change="handleChange">
    <button>add</button>
  </form>
</template>

<script>
export default {
  data(){
    return {
      file: ''
    }
  },
  methods: {
    handleChange(e){
      this.file = e.target.files[0]
    },
    async handleSubmit(){
      await this.$store.dispatch('images/uploadImage', this.file)
    }
  }
}
</script>

Vuex 动作发布到预签名的 url

actions: {
    async uploadImage(context, file){
      try {
        const res = await api.get('/upload', {
          headers: {
            Authorization: `Bearer ${localStorage.getItem('token')}`
          }
        })
        await axios.put(res.data.url, file, {
          headers: {
            'Content-Type': file.type
          }
        })
      }catch(err){
        console.log(err.message)
        context.commit('SET_ERROR', err.message, { root: true })
      }
    }
  }

Aws CORS 权限

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST"
        ],
        "AllowedOrigins": [
            "http://localhost:8080"
        ],
        "ExposeHeaders": []
    }
]

我收到“请求失败,状态码 400”错误。

标签: node.jsamazon-web-servicesvue.jsamazon-s3axios

解决方案


几周前我遇到了类似的情况,这就是我解决的方法

const formData = new FormData();
Object.entries(fields).forEach(([key, value]) => {
    formData.append(key, value);
});

formData.append('file', file.originFileObj);

axios.post(url, formData, {
    headers: {
        'Content-Type': 'multipart/form-data',
    },
})

fields来自对generate_presigned_post的调用

file是来自类型的对象File


推荐阅读