我正在尝试将文件直接上传到 Google Cloud Storage 存储桶。我通过 Ruby on Rails API ActiveStorage 设置成功创建了一个直接上传链接。
使用创建的直接上传链接,我尝试向前端客户端 (Next.js) 中的 Google Cloud Storage 存储桶发出
PUT
请求。
在我的前端客户端中,我使用
PUT
发出 fetch
请求并收到以下 CORS 错误:
在 Chrome 中:
访问获取 来自源“http://localhost:8080”的“https://storage.googleapis.com//?GoogleAccessId=
&Expires=1678985734&Signature=”已被 CORS 策略阻止: 对预检请求的响应未通过访问控制检查:否 请求中存在“Access-Control-Allow-Origin”标头 资源。如果不透明的响应满足您的需求,请设置请求的 模式设置为“no-cors”以在禁用 CORS 的情况下获取资源。
在 Safari 中:
Access-Control-Allow-Origin 不允许 Origin http://localhost:8080。状态代码:200 无法加载资源:Access-Control-Allow-Origin 不允许 Origin http://localhost:8080。状态代码:200
根据 Google Cloud 的 CORS 配置,这是我的存储桶的 CORS 策略:
[
{
"origin": ["http://localhost:8080"],
"method": ["GET", "PUT"],
"responseHeader": ["Origin", "Content-Type", "Content-MD5", "Content-Disposition"],
"maxAgeSeconds": 3600
}
]
我已通过运行以下命令确认存在此 CORS 配置:
gcloud storage buckets describe gs://<BUCKET_NAME> --format="default(cors)"
我在前端客户端中的直接上传获取非常简单:
const directUpload = async (directUpload: DirectUpload) => {
const response = await fetch(directUpload.url, {
method: 'PUT',
headers: JSON.parse(directUpload.headers),
body: file,
});
return response;
}
PUT
(来自网络选项卡)的请求标头如下:
Content-Disposition: inline; filename="logo.png"; filename*=UTF-8''logo.png
Content-Type: image/png
Origin: http://localhost:8080
Referer: http://localhost:8080/
Accept: */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.6 Safari/605.1.15
Content-MD5: y+5qHSqBo9Kmlkln9P0vAQ==
来自
PUT
请求的 GCS 响应标头(状态代码 403):
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
content-length: 363
content-type: application/xml; charset=UTF-8
date: Mon, 20 Mar 2023 16:39:30 GMT
server: UploadServer
x-guploader-uploadid: <UPLOAD_ID>
预检请求的请求标头:
:authority: storage.googleapis.com
:method: OPTIONS
:path: <DIRECT_UPLOAD_PATH>
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
access-control-request-headers: content-disposition,content-md5,content-type
access-control-request-method: PUT
cache-control: no-cache
origin: http://localhost:8080
pragma: no-cache
referer: http://localhost:8080/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
来自 预检请求的 GCS 的响应标头:
access-control-allow-headers: Content-Type,Content-MD5,Content-Disposition
access-control-allow-methods: GET,PUT
access-control-allow-origin: http://localhost:8080
access-control-max-age: 3600
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
cache-control: private, max-age=0
content-length: 0
content-type: text/html; charset=UTF-8
date: Thu, 16 Mar 2023 19:26:23 GMT
expires: Thu, 16 Mar 2023 19:26:23 GMT
server: UploadServer
vary: Origin
x-guploader-uploadid: <UPLOAD_ID>
我可以看到 Origin
标头应与我的存储桶 CORS 策略中的 origin 设置相匹配。 尝试的解决方案
将我的存储桶的 CORS 策略中的 "origin": ["http://localhost:8080"]
在本文中进行更改后,我能够成功向 Google Cloud Storage 发出
PUT
这涉及按照此处的活动存储指南将添加到
cache_control: "public, max-age=3600"
google
中我的
storage.yml
服务:https://edgeguides.rubyonrails.org/active_storage_overview.html#google-cloud-storage-service我还将
"Cache-Control"
添加到上传到我的 GCS 存储桶 CORS 策略的 responseHeader
列表中。
这导致向 GCS 成功发出PUT
请求,并将文件上传到我的存储桶。
在 Rails 中添加
cache_control
会强制使用 v4
(而不是
v2
)来生成签名 URL。有关签名 URL 的更多信息,请访问:https://cloud.google.com/storage/docs/access-control/signed-urls#types• 使用服务帐户身份验证进行 V4 签名:此签名机制如下所述。 • 使用服务帐户身份验证进行 V2 签名:这是用于创建签名 URL 的旧机制,不建议使用它。
当我在本地主机中开发时尝试从存储中“获取”静态文件时,我到达了这篇文章,我所做的解决方法是更新我的存储桶 CORS 策略,如下所示:
首先创建一个包含此内容的文件my_local_setup_for_CORS.json
:
考虑您正在使用的端口您计划访问的内容类型
[
{
"origin": ["http://localhost:8080"],
"responseHeader": ["Content-Type"],
"method": ["GET"],
"maxAgeSeconds": 3600
}
]
gsutil cors set my_local_setup_for_CORS.json gs://{name-of-your-bucket}
再次尝试时请记住强制重新加载“ctrl+f5”。
我通过安装 cors 节点模块并将其添加到请求的服务器上解决了该问题