Google云端存储签名网址 - 如何指定最大文件大小?

时间:2017-08-22 08:28:08

标签: http upload google-cloud-platform google-cloud-storage pre-signed-url

目标

我们希望用户能够将图片上传到Google云端存储。

问题

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

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

提议的解决方案

要实现直接上传,我们会在服务器上生成Signed URL。签名URL指定到期时间,并且只能与HTTP PUT动词一起使用。用户可以请求签名URL,然后 - 仅在有限时间内 - 将图像上载到签名URL指定的路径。

解决方案问题

有没有办法强制实施最大文件上传大小?显然我们希望避免用户在我们预期< 1MB文件时尝试上传20GB文件。

这似乎是一个明显的漏洞,但我仍然不知道在使用SignedURL时如何解决它。

使用政策文件(Stack Overflow answer)似乎有办法实现这一目标,但问题已超过2年了。

5 个答案:

答案 0 :(得分:4)

政策文件仍然是正确的答案。它们记录在此处:https://cloud.google.com/storage/docs/xml-api/post-object#policydocument

您需要的政策文件的重要部分是:

["content-length-range", <min_range>, <max_range>].

答案 1 :(得分:1)

签署内容长度应该可以解决问题。

即使 content-length 设置为较低的值,Google Cloud 也不允许上传较大的文件。

签名的 url 选项应如下所示:

const writeOptions: GetSignedUrlConfig = {
  version: 'v4',
  action: 'write',
  expires: Date.now() + 900000, // 15 minutes
  extensionHeaders: {
    "content-length": length // desired length in bytes
  }
}

答案 2 :(得分:0)

您可以使用X-Upload-Content-Length代替Content-LengthSee blog post here

在服务器端(Java):

Map<String, String> extensionHeaders = new HashMap<>();
extensionHeaders.put("X-Upload-Content-Length", "" + contentLength);
extensionHeaders.put("Content-Type", "application/octet-stream");

var url =
  storage.signUrl(
    blobInfo,
    15,
    TimeUnit.MINUTES,
    Storage.SignUrlOption.httpMethod(HttpMethod.PUT),
    Storage.SignUrlOption.withExtHeaders(extensionHeaders),
    Storage.SignUrlOption.withV4Signature()
  );

在客户端(打字稿):

const response = await fetch(url, {
  method: 'PUT',
  headers: {
    'X-Upload-Content-Length': `${file.size}`,
    'Content-Type': 'application/octet-stream',
  },
  body: file,
});

您将需要在存储桶上设置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
  }
]

答案 3 :(得分:0)

对于今天所有观看遮阳篷的人,请注意x-goog-content-length-range:0,25000是将PUT的上传大小限制在0到25000字节之间的有效方法

X-Upload-Content-Length

不起作用,您仍然可以上传较大的文件

答案 4 :(得分:0)

我在 NodeJS 中工作的代码遵循 https://blog.koliseo.com/limit-the-size-of-uploaded-files-with-signed-urls-on-google-cloud-storage/。您必须使用版本 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;
  }

在前端,我们必须在头X-Upload-Content-Length中设置相同数量的Size


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);
  });
}

并且不要忘记在 responseHeader

中配置 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"]}]