我正在嘗試使用預簽名的 url 在 Scaleway 物件存盤(S3 兼容)上進行分段上傳,并且在瀏覽器生成的預檢請求中出現錯誤 (403),但我的 CORS 設定似乎正確設定。(基本上是允許的標題和來源的通配符)。
該錯誤帶有 403 狀態代碼,如下所示:
<?xml version='1.0' encoding='UTF-8'?>
<Error><Code>AccessDenied</Code><Message>Access Denied.</Message><RequestId>...</RequestId></Error>
我現在在這個問題上停留了一段時間,我嘗試從我的瀏覽器復制飛行前請求以在其他地方重現它并嘗試稍微調整它。從飛行前請求的 url 中洗掉查詢引數會使請求成功(回傳 200 并Access-Control-Allow-*正確設定回應標頭)但這顯然不是瀏覽器行為......
這不起作用(秘密、密鑰和名稱已更改)
curl 'https://bucket-name.s3.fr-par.scw.cloud/tmp-screenshot-2021-01-20-at-16-21-33.png?AWSAccessKeyId=XXXXXXXXXXXXXXXXXXXX&Expires=1638217988&Signature=NnP1XLlcvPzZnsUgDAzm1Uhxri0=&partNumber=1&uploadId=OWI1NWY5ZGrtYzE3MS00MjcyLWI2NDAtNjFkYTM1MTRiZTcx' -X OPTIONS -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: http://domain.tech/' -H 'Access-Control-Request-Method: PUT' -H 'Origin: http://domain.tech' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: no-cors' -H 'Sec-Fetch-Site: cross-site' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'
此作品(秘密、密鑰和名稱已更改)
curl 'https://bucket-name.s3.fr-par.scw.cloud/tmp-screenshot-2021-01-20-at-16-21-33.png' -X OPTIONS -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0' -H 'Accept: */*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Referer: http://domain.tech/' -H 'Access-Control-Request-Method: PUT' -H 'Origin: http://domain.tech' -H 'DNT: 1' -H 'Connection: keep-alive' -H 'Sec-Fetch-Dest: empty' -H 'Sec-Fetch-Mode: no-cors' -H 'Sec-Fetch-Site: cross-site' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'
網址來自aws-sdk并以這種方式生成:
const S3Client = new S3({
credentials: {
accessKeyId: env.SCW_ACCESS_KEY,
secretAccessKey: env.SCW_SECRET_KEY,
},
endpoint: `https://s3.${env.SCW_REGION}.scw.cloud`,
})
S3Client.getSignedUrlPromise('uploadPart', {
Bucket: bucket,
Key: key,
UploadId: multipartUpload.UploadId,
PartNumber: idx 1,
})
并在前端使用這種方式:
// url being the url generated in backend as demonstrated above
const response = await fetch(url, {
method: 'PUT',
body: filePart,
signal: abortController.signal,
})
如果有人能幫我解決這個或那個,那就太好了!
uj5u.com熱心網友回復:
事實證明,Scaleway Object Storage 在這種情況下并不完全兼容 S3。
這是一個解決方法:
- 安裝
aws4庫以輕松簽署請求(或按照此 scaleway 檔案手動簽署您的請求) - 形成你的要求完全一樣在每陳述這個其他scaleway檔案(這是
aws-sdk行為不同,它會生成帶有URLAWSAccessKeyId,Expires并Signature查詢引數是事業scaleway API失敗。Scaleway API只想要partNumber和uploadId)。 - 將生成的 url 和 headers 回傳給前端
// Backend code
const signedRequest = aws4.sign(
{
method: 'PUT',
path: `/${key}?partNumber=${idx 1}&uploadId=${
multipartUpload.UploadId
}`,
service: 's3',
region: env.SCW_REGION,
host: `${bucket}.s3.${env.SCW_REGION}.scw.cloud`,
},
{
accessKeyId: env.SCW_ACCESS_KEY,
secretAccessKey: env.SCW_SECRET_KEY,
},
)
return {
url: `https://${signedRequest.host}${signedRequest.path}`,
headers: Object.keys(signedRequest.headers).map((key) => ({
key,
value: signedRequest.headers[key] as string,
})),
}
然后在前端:
// Frontend code
const headers = signedRequest.headers.reduce<Record<string, string>>(
(acc, h) => ({ ...acc, [h.key]: h.value }),
{},
)
const response = await fetch(signedRequest.url, {
method: 'PUT',
body: filePart,
headers,
signal: abortController.signal,
})
正如我直接與他們的支持團隊討論的那樣,Scaleway 知道這個問題,并且他們正在付出一些努力以盡可能地與 S3 兼容。當您閱讀本文時,此問題可能已解決。感謝他們的快速回應時間和認真對待這一點。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/371805.html
