我正試圖用JavaScript fetch()將檔案上傳到Amazon S3的預設網址,如下所示(從chrome開發工具中復制粘貼)
fetch("https://.....amazonaws.com/.../copy.mp3?AWSAccessKeyId=...& Signature=...& Expires=1631443785", {
"headers"/span>: {
"內容型別": "audio/mpeg",
"sec-ch-ua": "Google Chrome";v="93", " Not;A Brand"; v="99", "Chromium";v="93"",
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": ""macOS""。
},
"referrer": "http://localhost:3000/",
"referrerPolicy": "strict-origin-when-cross-origin",
"method": "PUT"。
"模式"。"cors",
"憑證"。"省略"。
});
并且回傳以下錯誤 "SignatureDoesNotMatch":
。<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>我們計算的請求簽名與你提供的簽名不一致。
檢查你的密鑰和簽名方法。</Message>
<AWSAccessKeyId>...</AWSAccessKeyId>
<StringToSign>GET 1631443785 ..../copy.mp3</StringToSign>
...
</Error>
錯誤中的StringToSign說這是一個 "GET "請求,而我認為我是用fetch()發送一個PUT。
此外,我嘗試運行$curl,如:
$curl --request PUT-upload-file copy. mp3 https://....'/span>。
并且成功了。
我有什么地方做錯了嗎?
提前感謝你。我已經在這里被封鎖了2天了:(
)uj5u.com熱心網友回復:
在aws檔案中,有一個關于如何使用fetch的例子:
。
//為Node.js匯入必要的AWS SDK客戶端和命令。
import {
CreateBucketCommand。
DeleteObjectCommand。
PutObjectCommand。
DeleteBucketCommand }
from "@aws-sdk/client-s3"。
import { s3Client } from "./libs/s3Client.js"; // Helper function that create Amazon S3 service client module.
import { getSignedUrl } from "@aws-sdk/s3-request-presigner"。
import fetch from "node-fetch"。
//設定引數
///為亞馬遜簡單存盤服務(Amazon S3)桶和密鑰創建一個隨機名稱。
export const bucketParams = {
Bucket。`test-bucket-${Math. ceil(Math.random() * 10 ** 10)}`,
Key: `test-object-${Math. ceil(Math.random() * 10 ** 10)}`,
Body: "BODY"。
};
export const run = async ( ) => {
try {
//創建一個Amazon S3 bucket.。
console.log(`Creating bucket ${bucketParams.Bucket}`) 。
await s3Client. send(new CreateBucketCommand({ Bucket: bucketParams. Bucket })。
console.log(`Waiting for "${bucketParams.Bucket}" bucket creation...`)。
} catch (err) {
console.log("Error creating bucket"/span>, err)。
}
try {
//創建命令。
const command = new PutObjectCommand(bucketParams)。
//創建預設的URL.。
const signedUrl = await getSignedUrl(s3Client, command, {
expiresIn: 3600,
});
console.log(
`。
將"${bucketParams.Key}"使用signedUrl與主體"${bucketParams.Body}"放在v3中`。
);
console.log(signedUrl)。
const response = await fetch(signedUrl)。
console.log(
`.
由簽名的URL回傳的回應。${await response.text()}
`
);
return回應。
} catch (err) {
console.log("Error creating presigned URL"/span>, err)。
}
try {
//洗掉物件。
console.log(`)
洗掉物件"${bucketParams.Key}"}從bucket`)。)
await s3Client.send(
new DeleteObjectCommand({ Bucket: bucketParams. Bucket, Key: bucketParams.Key })
);
} catch (err) {
console.log("Error deleting object"/span>, err)。
}
try {
//洗掉Amazon S3 bucket.。
console.log(`)
洗掉桶${bucketParams.Bucket}`)。)
await s3. send(new DeleteBucketCommand({ Bucket: bucketParams. Bucket })。
} catch (err) {
console.log("Error deleting bucket"/span>, err)。
}
};
run()。
這可能比你需要的多一點。更多資訊在這里
。uj5u.com熱心網友回復:
我想出了如何用POST請求上傳(而不是PUT,這是一個變通的解決方案),下面是方法:
對于你的瀏覽器來說:
const formData = new FormData();
Object.keys(signedPost.fields)。 forEach(key => {
formData.append(key, signedPost.fields[key]) 。
});
//你必須把檔案放在最后的位置,否則S3會抱怨:。
//"Bucket POST必須包含一個名為'key'的欄位。 如果指定了,請檢查欄位的順序。" // "Bucket POST必須包含一個名為'key'的欄位。
//如果任何為Amazon S3作業的人看到這個錯誤味精,請修復它。// 這很讓人困惑。用E.g "Put file in the last position "代替。
formData.append("file"/span>, file)。
fetch(
signedPost.url。
{
method: "POST"。
body: formData,
}
).then(
res => console.log(res)。
).catch((error) =>/span> {
console.log(錯誤)。
拋出錯誤。
});
對于你的服務器。使用generate_presigned_post API而不是generate_presigned_url。例如:
respone = s3_client.generate_presigned_post(
Bucket=bucket。
Key=key。
ExpiresIn=expires_in_s,
)
到目前為止,我對我原來的問題的理解:
對于我原來的 "SignatureDoesNotMatch "阻塞飛行前的OPTIONS請求問題,后請求跳過了OPTIONS請求。因此,后預簽的作業方式就可以解決了。這也是為什么$curl PUT可以作業,但Chrome中的javascript PUT對于完全相同的預簽名url的PUT請求卻不能作業。$curl不運行預檢OPTION。但是對于Chrome中的javascript,它運行(a)發送OPTIONS(b)發送PUT,而我在(a)中被阻止了。正如(1)中的討論,7年前就有人提出了幾乎相同的問題,而我們在這個問題上仍然沒有一個好的答案。如果有一個作業崗位的解決方案,我會讓它過去,而不是在這個問題上浪費更多時間。然而,如果有必要的話,亞馬遜的人可以為它創建一個票據,那將是非常好的。
參考:
- (1) 這里是一個非常類似的問題,但并不完全相同。
- (2) 來自亞馬遜的預設URL實體 。
- (3)
generate_presigned_post和generate_presigned_url之間有什么區別?。 。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/319194.html
標籤:
