js 使用預簽名(presigned) url 上傳文件到 AWS S3服務(解決生成的文件格式錯誤問題)

  • 背景
    項目裏有圖片上傳的需求,具體實現是後端生成presigned url(預簽名url,裏面包含上傳到AWS S3所需要的一些認證標識信息)給到前端,前端通過這個URL將文件上傳到雲服務上。但是上傳成功後,從CDN上下載下來的文件打不開,而且只有前端有這個問題,客戶端可以正常上傳,一開始以爲是框架問題,而且亞馬遜官方也沒有直接上傳相關的文檔(都是使用SDK的方式上傳),所以問題很難定位,後來在github上找到了方案。
  • 相關步驟
  1. 從後端獲取presigned url ,亞馬遜官網有Java、PHP、node等生成presigned url的文檔
    在這裏插入圖片描述
  2. 使用presigned url上傳圖片,前端使用的是element UI + axios, 這裏使用的element UI 自定義上傳的方式,特別需要注意的就是直接上傳文件,不要用formdata的格式上傳

HTML部分

 <el-upload
     class="avatar-uploader"
     action="123"
    :http-request="upload"
    :before-upload="beforeAvatarUpload">
    <img v-if="params.defaultImgUrl" :src="params.defaultImgUrl" class="avatar">
    <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>

js 部分

upload(res)
{
    let file = res.file;  //注意:直接上傳file文件,不要用FormData對象的形式傳
    let config = {
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    };
    //從接口獲取presigned url
    getUploadUrl({uploadType: 6}).then(res => {
        let result = res.data;

        if (result.code === 0) {
            const info = JSON.parse(result.msg);
            //需要用put方法上傳,post會報405,aws官方規定是put方法
            axios.put(info.presignedUrl, file, config)
                .then(res => {
                    if (res.status == 200) {
                        this.params.defaultImgUrl = info.cdnUrl;
                    }
                }).catch(
                err => {
                    console.log(err)
                }
            )
        }
    }).catch(err => {
        console.log('get upload info', err)
    })
}
  1. 返回200狀態碼即表示上傳成功
    在這裏插入圖片描述
  • 坑點
    一般圖片、文件上傳都是使用FormData對象傳遞二進制文件,所以筆者一開始也是採用的這種方式上傳到AWS上,但是上傳完之後,下載後的圖片無法打開,將其二進制數據與原文件二級制數進行對比,發現有額外的二進制數據
    在這裏插入圖片描述
    後來在github上找到了解決方案,原來使FormData對象上傳文件到aws上會損壞原文件的二進制數據,直接上傳文件對象就行

附上參考的解決方案github地址:
https://github.com/aws/aws-sdk-js/issues/547

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章