Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Http 谷歌云存储签名URL——如何指定最大文件大小?_Http_Upload_Google Cloud Platform_Google Cloud Storage_Pre Signed Url - Fatal编程技术网

Http 谷歌云存储签名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指定的路径 解决方案的问题 有没有办法强制执行最大文件上载大小?显然,我们希望

目标

我们希望用户能够上传图像到谷歌云存储

问题

我们可以通过服务器作为中间人间接实现这一点——首先,用户上传到我们的服务器,然后我们的特权服务器可以上传到云存储

然而,我们认为这是不必要的慢,相反,我们希望用户直接上传到云存储

建议的解决方案

为了实现直接上传,我们在服务器上生成一个。签名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
  }
}