Http 谷歌云存储签名URL——如何指定最大文件大小?
目标 我们希望用户能够上传图像到谷歌云存储 问题 我们可以通过服务器作为中间人间接实现这一点——首先,用户上传到我们的服务器,然后我们的特权服务器可以上传到云存储 然而,我们认为这是不必要的慢,相反,我们希望用户直接上传到云存储 建议的解决方案 为了实现直接上传,我们在服务器上生成一个。签名URL指定过期时间,并且只能与HTTP PUT谓词一起使用。用户可以请求签名URL,然后(仅在有限的时间内)将图像上载到签名URL指定的路径 解决方案的问题Http 谷歌云存储签名URL——如何指定最大文件大小?,http,upload,google-cloud-platform,google-cloud-storage,pre-signed-url,Http,Upload,Google Cloud Platform,Google Cloud Storage,Pre Signed Url,目标 我们希望用户能够上传图像到谷歌云存储 问题 我们可以通过服务器作为中间人间接实现这一点——首先,用户上传到我们的服务器,然后我们的特权服务器可以上传到云存储 然而,我们认为这是不必要的慢,相反,我们希望用户直接上传到云存储 建议的解决方案 为了实现直接上传,我们在服务器上生成一个。签名URL指定过期时间,并且只能与HTTP PUT谓词一起使用。用户可以请求签名URL,然后(仅在有限的时间内)将图像上载到签名URL指定的路径 解决方案的问题 有没有办法强制执行最大文件上载大小?显然,我们希望
有没有办法强制执行最大文件上载大小?显然,我们希望避免用户试图上传20GB文件,因为我们认为策略文档仍然是正确的答案。它们记录在这里: 您需要的政策文件的重要部分是:
["content-length-range", <min_range>, <max_range>].
[“内容长度范围”,]。
您可以使用X-Upload-Content-Length
而不是Content-Length
在服务器端(Java):
您需要在存储桶上设置cors策略:
[
{
"origin": ["https://your-website.com"],
"responseHeader": [
"Content-Type",
"Access-Control-Allow-Origin",
"X-Upload-Content-Length",
"x-goog-resumable"
],
"method": ["PUT", "OPTIONS"],
"maxAgeSeconds": 3600
}
]
对于今天看到答案的所有人,请注意 是一种将上传大小限制在0到25000字节云存储之间的方法
X-Upload-Content-Length
将无法工作,您仍然可以上载更大的文件我在NodeJS中的工作代码如下。您必须使用版本v4
public async getPreSignedUrlForUpload(
fileName: string,
contentType: string,
size: number,
bucketName: string = this.configService.get('DEFAULT_BUCKET_NAME'),
): Promise<string> {
const bucket = this.storage.bucket(bucketName);
const file = bucket.file(fileName);
const response = await file.getSignedUrl({
action: 'write',
contentType,
extensionHeaders: {
'X-Upload-Content-Length': size,
},
expires: Date.now() + 60 * 1000, // 1 minute
version: 'v4',
});
const signedUrl = this.maskSignedUrl(response[0], bucketName);
return signedUrl;
}
另外,不要忘记在GS CORS
gsutil cors get gs://asia-item-images
[{"maxAgeSeconds": 3600, "method": ["GET", "OPTIONS", "PUT"], "origin": ["*"], "responseHeader": ["Content-Type", "Access-Control-Allow-Origin", "X-Upload-Content-Length", "X-Goog-Resumable"]}]
签名内容长度应该可以做到这一点 即使内容长度设置为较低的值,谷歌云也不允许上传较大的文件 以下是签名url选项的外观:
const writeOptions: GetSignedUrlConfig = {
version: 'v4',
action: 'write',
expires: Date.now() + 900000, // 15 minutes
extensionHeaders: {
"content-length": length // desired length in bytes
}
}
同一链接说:“注意:除非您需要使用HTML表单(通常通过web浏览器)上传对象,否则强烈建议使用PUT对象而不是POST。”。但是,没有为PUT对象定义
内容长度范围。这是一个包含但未记录的功能吗?不,不幸的是,它只存在于POST中。所以谷歌建议使用PUT将对象上传到云存储,但不允许您指定最大文件大小???看起来PUT完全没用了…我测试了x-goog-content-length-range
这个,它做的是截断上传的文件,并且不会在错误的大小上取消。这对我有用!!这对我也很有用。此链接的更多详细信息:这允许上传超过所需限制,签名时只需填写X-Upload-Content-Length,在实际上传时设置相同的值。@RaduDiță签名在服务器端完成,而不是在客户端完成。这样做的目的是在签名之前验证内容长度,如果内容长度无效,则抛出异常。@NachoColoma即使检查是在服务器端完成的,也可以在上载时躺在客户端。GCS不检查提供的X-Upload-Content-Length是否为实际内容长度。例如,您可以获得1MB的有效签名并上载2MB文档。我能让地面军事系统真正阻止上传的唯一方法是使用内容长度。这对我来说很有效。它也适用于PUT请求
public async getPreSignedUrlForUpload(
fileName: string,
contentType: string,
size: number,
bucketName: string = this.configService.get('DEFAULT_BUCKET_NAME'),
): Promise<string> {
const bucket = this.storage.bucket(bucketName);
const file = bucket.file(fileName);
const response = await file.getSignedUrl({
action: 'write',
contentType,
extensionHeaders: {
'X-Upload-Content-Length': size,
},
expires: Date.now() + 60 * 1000, // 1 minute
version: 'v4',
});
const signedUrl = this.maskSignedUrl(response[0], bucketName);
return signedUrl;
}
export async function uploadFileToGCP(
signedUrl: string,
file: any
): Promise<any> {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.withCredentials = process.env.NODE_ENV === 'production';
xhr.addEventListener('readystatechange', function () {
if (this.readyState === 4) {
resolve(this.responseText);
}
});
xhr.open('PUT', signedUrl, true);
xhr.setRequestHeader('Content-Type', file.type);
xhr.setRequestHeader('X-Upload-Content-Length', file.size);
xhr.send(file);
});
}
gsutil cors get gs://asia-item-images
[{"maxAgeSeconds": 3600, "method": ["GET", "OPTIONS", "PUT"], "origin": ["*"], "responseHeader": ["Content-Type", "Access-Control-Allow-Origin", "X-Upload-Content-Length", "X-Goog-Resumable"]}]
const writeOptions: GetSignedUrlConfig = {
version: 'v4',
action: 'write',
expires: Date.now() + 900000, // 15 minutes
extensionHeaders: {
"content-length": length // desired length in bytes
}
}