我正在尝试通过 gcs、node、vue 每个https://cloud.google.com/storage/docs/performing-resumable-uploads执行单个块可恢复上传。我能够生成signedUrl,但是当我尝试通过客户端放置或发布到signedUrl 时出现错误。
如果导航到 signedUrl,浏览器会显示以下错误:
<Error>
<Code>MalformedSecurityHeader</Code>
<Message>Your request has a malformed header.</Message>
<ParameterName>content-type</ParameterName>
<Details>Header was included in signedheaders, but not in the request.</Details>
</Error>
在控制台中,我收到以下错误(所有这些中的 domain.appspot 和 domain.iam 都设置为我的存储桶名称。我只是在这里替换/隐藏它以防万一):
在 'https://storage.googleapis.com/domain.appspot.com/media/20161017_213931.mp4?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=gcs-server%40domain.iam 访问 XMLHttpRequest .gserviceaccount.com%2F20211213%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20211213T202005Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost%3Bx-goog-resumable&X-Goog-Signature=920390253e558265309a73ceda3ac981c56d40580c8103d41dd191478bb7186b3aea742891f0fc50ad8c766ff1e262c1f012f021f7687699873f98cf244799539ec86f3f600eb9b2e849f869de677ae8bc75a0343eb474f50e12dd4bebc9594c0d4b309bf94b55a1a9c1e3971004c62ed11ebdb328813d8c860d70714feade4b940b7f14c015d45eaa87c816c83d3ba2a1b41783dcda9a9f9ffe09de6ccd47a0c1d292ee0e4c0e1fa0a61d1109207f8a9b9c67d41ae8797bcacb8102a5b3e09a4c108d07d29697bddbe638b32117c078ec180f50c021b5094a163034f3c3d799295f6dd78279a4fb4f0a03d3037333fdf3a03bacc2bd8edb02c2f63974707561' from origin 'http://localhost:8081' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.Access-Control-Allow-Origin' 标头出现在请求的资源上。Access-Control-Allow-Origin' 标头出现在请求的资源上。
// 节点/后端
import { Storage } from '@google-cloud/storage'
const storage = new Storage({
keyFilename: process.env.GOOGLE_APPLICATION_CREDENTIALS
})
const bucketName = 'xxxx.appspot.com'
async function createResumableUrl (file) {
const blob = storage.bucket(bucketName).file(`media/${file.originalname}`)
const options = {
version: 'v4',
action: 'resumable',
contentType: 'application/octet-stream',
expires: Date.now() + 15 * 60 * 1000 // 15 minutes
}
const [signedUrl] = await blob.getSignedUrl(options)
return signedUrl
}
// vue/quasar 前端表单
<q-form
enctype="multipart/form-data"
>
<q-file
v-if="!initFile"
label="Select a file for Upload"
dense
outlined
rounded
no-error-icon
hide-bottom-space
bg-color="grey-1"
class="q-pt-sm q-mb-md"
@input="mediaAction"
>
<template v-if="media.location" v-slot:append>
<q-icon name="mdi-autorenew" @click.stop="" class="cursor-pointer" />
</template>
<template v-else v-slot:append>
<q-icon name="mdi-plus" @click.stop="" class="cursor-pointer" />
</template>
<template v-if="uploaderHint" v-slot:hint>
{{ uploaderHint }}
</template>
</q-file>
<q-btn
unelevated
dense
size="0.6rem"
color="primary"
class="q-py-xs q-px-sm q-mr-md"
@click="onOKClick"
>
<span>
<q-icon name="mdi-upload-outline" class="q-mr-xs" />
<span v-if="initFile">Update</span>
<span v-else>Upload</span>
</span>
</q-btn>
</q-form>
// vue/quasar 方法
methods: {
async onOKClick () {
const formData = new FormData()
formData.append('file', this.selectedMedia)
const signedUrl = await this.$store.dispatch('media/createResumableUrl', formData)
// signedUrl is present
// console.log(signedUrl.data)
const upload = await this.$api.put(signedUrl.data, formData, {
withCredentials: false,
headers: {
'Content-Type': 'application/octet-stream',
'Access-Control-Allow-Origin': 'http://localhost:8081'
}
})
}
}
// gcs 存储桶配置
[
{
"origin": [
"*"
],
"responseHeader": [
"Content-Type",
"x-goog-resumable",
"Access-Control-Allow-Origin"
],
"method": ["PUT", "GET", "HEAD", "DELETE", "POST", "OPTIONS"],
"maxAgeSeconds": 15
}
]
我尝试过的事情:
- 我试图用帖子而不是 put 来发出客户请求
- 我尝试将 'Content-Range': 'bytes *' 添加到所有请求
- 我已经尝试将源添加到节点请求的 signedUrl 并且我已经尝试将客户端请求和 cors 存储桶配置匹配为都相同。我已经用端口尝试过这个,没有端口和'*':
// 节点
const options = {
version: 'v4',
origin: 'http://localhost',
action: 'resumable',
contentType: 'application/octet-stream',
expires: Date.now() + 15 * 60 * 1000 // 15 minutes
}
// 客户
const upload = await this.$api.put(signedUrl.data, formData, {
withCredentials: false,
headers: {
'Content-Type': 'application/octet-stream',
'Access-Control-Allow-Origin': 'http://localhost'
}
})
// cors桶配置
[
{
"origin": [
"http://localhost"
],
"responseHeader": [
"Content-Type",
"x-goog-resumable",
"Access-Control-Allow-Origin"
],
"method": ["PUT", "GET", "HEAD", "DELETE", "POST", "OPTIONS"],
"maxAgeSeconds": 1
}
]
// 预检信息
响应标头:
访问控制允许标头:内容类型、x-goog-resumable、访问控制允许来源访问控制允许方法:PUT、GET、HEAD、DELETE、POST、OPTIONS
访问控制允许-来源:* 访问控制最大年龄:15 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"; 马=2592000;v="46,43" 缓存控制:私有,max-age=0 内容长度:0 内容类型:文本/html;charset=UTF-8 date: Tue, 14 Dec 2021 11:03:32 GMT expires: Tue, 14 Dec 2021 11:03:32 GMT server: UploadServer x-guploader-uploadid: ADPycdsNLbraMoNCtWBN2etY5999RcEAzpzumosHd6kQb-O00g53MwwY1JciRK7UauOU4mbLo84Tmasvl-57QCo41NoP8s-8Pg
请求标头
:authority: storage.googleapis.com
:method: 选项
:path: /domain.appspot.com/media/20161017_213931.mp4?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=gcs-server%40origin-sports.iam.gserviceaccount.com%2F20211214%2Fauto% 2Fstorage%2Fgoog4_request&X-Goog-Date=20211214T110332Z&X-Goog-Expires=900&X-Goog-SignedHeaders=content-type%3Bhost%3Bx-goog-resumable&X-Goog-Signature=40d4d9bcfd6b62786144968bf3e7fe3a2820d7a42ab6a510832ddbea3aac65bf31ca59f85694125ac98da6c13d1ba740302f88164d5c53ecdd1e40eb4bdb431f34d103c2f5f2f7d0018a9ef0e4ff15978d834b4b3a2b17699a0dc7f8fabc49f99129d7d9b8de4341c0f6883c03a5ce16303811b278ca72f080167d0f4a1e7cc98076e473b7a65043976ddcf87532f52e9d2efefd48fae38bd3742e3e21ef86702b00cfe71b8b08fa506b886183146c94d61b747150ad2b5ae6ea668a5750dce27c5f212e9b60002e5bd09af0fee43a3566606f9063113a1f14d51d22af65eaf6503270f696e9bf50c9015c2af65ef8ec994f1949a4081d5872b2be09cb070e68
:scheme: https 接受: /
接受编码: gzip, deflate, br 接受语言: en-US,en;q=0.9 access-control-request-headers: access-control-allow-origin,content-type,x -goog-resumable access-control-request-method: PUT cache-control: no-cache origin: http://localhost:8081 pragma: no-cache referer: http://localhost:8081/sec-fetch-dest: empty sec-fetch-mode: cors sec-fetch-site: cross-site user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36
我不经常在这里发帖,所以如果您需要其他任何内容或者我是否需要重组这个问题,请告诉我。
// 我发现没有用的相关事情