我正在嘗試使用 getSignedUrlPromise() 將檔案上傳到 AWS S3 以獲取訪問鏈接,因為存盤桶是完全私有的,我希望它只能通過服務器使用 getSignedUrlPromise() 生成的鏈接進行訪問。
當我嘗試向該鏈接發出 Put 請求時出現問題,因為我收到以下錯誤,我也將收到的回復留給您。

下面是在 nodeJS 中配置 aws 的代碼:
import AWS from 'aws-sdk';
const bucketName = 'atlasfitness-progress';
const region =process.env.AWS_REGION;
const accessKeyId = process.env.AWS_ACCESS_KEY
const secretAccessKey = process.env.AWS_SECRET_KEY
const URL_EXPIRATION_TIME = 60; // in seconds
const s3 = new AWS.S3({
region,
accessKeyId,
secretAccessKey,
signatureVersion: 'v4'
})
export const generatePreSignedPutUrl = async (fileName, fileType) => {
const params = ({
Bucket: bucketName,
Key: fileName,
Expires: 60
})
const url = await s3.getSignedUrlPromise('putObject', params);
return url;
}
然后我有一個快速控制器在請求時發送鏈接:
routerProgress.post('/prepare_s3', verifyJWT, async (req, res) => {
res.send({url: await generatePreSignedPutUrl(req.body.fileName, req.body.fileType)});
})
export { routerProgress };
但是問題出在前端,這里是首先請求鏈接然后嘗試將檔案上傳到S3的函式。
const upload = async (e) => {
e.preventDefault();
await JWT.checkJWT();
const requestObject = {
fileName: frontPhoto.name,
fileType: frontPhoto.type,
token: JWT.getToken()
};
const url = (await axiosReq.post(`${serverPath}/prepare_s3`, requestObject)).data.url;
//Following function is the one that doesn't work
const response = await fetch(url, {
method: "PUT",
headers: {
"Content-Type": "multipart/form-data"
},
body: frontPhoto
});
console.log(response);
}
一切都完成了,我可以說我是 AWS 的新手,所以很可能我在沒有意識到的情況下造成了相當嚴重的錯誤,但是我在這里被阻止了很多天,我開始變得絕望。因此,如果有人檢測到錯誤或知道我如何使其作業,我將非常感謝您的幫助。
uj5u.com熱心網友回復:
關于您的代碼,我注意到的第一件事是您await進行了異步操作,但不提供例外。這是非常糟糕的做法,因為它隱藏了可能的失敗。經驗法則是:無論何時需要await結果,都將呼叫包裝在 try/catch 塊中。
在上面的服務器端代碼中,您有兩個等待可能會失敗,如果它們失敗,它們生成的任何錯誤都會丟失。
更好的策略是:
export const generatePreSignedPutUrl = async (fileName, fileType) => {
const params = ({
Bucket: bucketName,
Key: fileName,
Expires: 60
})
let url;
try {
url = await s3.getSignedUrlPromise('putObject', params);
} catch (err) {
// do something with the error here
// and abort the operation.
return;
}
return url;
}
在你的 POST 路線中:
routerProgress.post('/prepare_s3', verifyJWT, async (req, res) => {
let url;
try {
url = await generatePreSignedPutUrl(req.body.fileName, req.body.fileType);
} catch (err) {
res.status(500).send({ ok: false, error: `failed to get url: ${err}` });
return;
}
res.send({ url });
})
在您的客戶端代碼中,遵循相同的策略。至少,這會讓您更好地了解代碼失敗的地方。
要記住兩件事:
使用
async關鍵字宣告的函式不會回傳預期結果的值;它們回傳預期結果的 Promise,并且像所有 Promise 一樣,可以鏈接到兩者.catch()和.then()子句。當從另一個異步函式中呼叫異步函式時,您必須對遇到的任何例外進行處理,因為由于其性質,Promise 不共享任何周圍的運行時背景關系,這將允許您在更高級別捕獲任何例外。
因此,您可以在異步函式中使用 Promise“thenable”鏈接或 try/catch 塊來捕獲錯誤,但如果您選擇不這樣做,您將面臨丟失代碼中生成的任何錯誤的風險。
uj5u.com熱心網友回復:
下面是如何創建可用于 PUT MP4 檔案的預簽名 URL 的示例。
const AWS = require('aws-sdk');
const s3 = new AWS.S3({
apiVersion: '2010-12-01',
signatureVersion: 'v4',
region: process.env.AWS_DEFAULT_REGION || 'us-east-1',
});
const params = {
Bucket: 'mybucket',
Key: 'videos/sample.mp4',
Expires: 1000,
ContentType: 'video/mp4',
};
const url = s3.getSignedUrl('putObject', params);
console.log(url);
生成的 URL 將如下所示:
https://mybucket.s3.amazonaws.com/videos/sample.mp4?
Content-Type=video/mp4&
X-Amz-Algorithm=AWS4-HMAC-SHA256&
X-Amz-Credential=AKIASAMPLESAMPLE/20200303/us-east-1/s3/aws4_request&
X-Amz-Date=20211011T090807Z&
X-Amz-Expires=1000&
X-Amz-Signature=long-sig-here&
X-Amz-SignedHeaders=host
您可以通過使用 curl 上傳 sample.mp4 來測驗此 URL,如下所示:
curl -X PUT -T sample.mp4 -H "Content-Type: video/mp4" "<signed url>"
一些注意事項:
- 希望您可以使用此代碼來找出問題所在。
- 預簽名 URL 由 SDK 在本地創建,因此無需異步。
- 我建議創建預先簽名的 URL,然后在測驗瀏覽器客戶端之前使用 curl 測驗 PUT ,以確保 curl 正常作業。這樣,您就會知道是將注意力集中在預簽名 URL 的生成上,還是集中在客戶端內預簽名 URL 的使用上。
如果您嘗試通過 curl 上傳失敗并顯示拒絕訪問,請檢查:
- 預簽名 URL 尚未過期(它們有時間限制)
- 您用于簽署 URL 的 AWS 憑證允許 PutObject 到該 S3 存盤桶
- S3 存盤桶策略不會明確拒絕您的請求
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/318849.html
上一篇:容器與用戶本地系統檔案路徑的通信
