【问题标题】:Google Cloud Storage creating content links with inconsistent behaviorGoogle Cloud Storage 创建行为不一致的内容链接
【发布时间】:2017-04-02 13:28:26
【问题描述】:

我正在开发一个使用 Google Cloud Storage 的项目,以允许用户使用 Node.js 将媒体文件上传到预定义的存储桶中。我一直在用小的 .jpg 文件进行测试。我还使用gsutil 将存储桶权限设置为公开。

首先,所有文件都生成了下载文件的链接。通过对文档的调查,我了解到我可以在使用gsutil CLI 上传后明确设置每个文件的Content-Type。当我使用此过程将文件类型设置为'image/jpeg' 时,链接行为更改为在浏览器中显示图像。但这仅在使用 gsutil 更新元数据之前未单击链接的情况下才有效。我认为这可能是由于浏览器缓存造成的,但该行为在隐身浏览器中重复。

使用gsutil 设置mime 类型无论如何都是不切实际的,因此我修改了我的节点服务器POST 函数中的代码,以便在上传时使用名为npm 的模块mime 设置元数据。代码如下:

app.post('/api/assets', multer.single('qqfile'), function (req, res, next) {
    console.log(req.file);

    if (!req.file) {
        return ('400 - No file uploaded.');
    }

    // Create a new blob in the bucket and upload the file data.
    var blob = bucket.file(req.file.originalname);
    var blobStream = blob.createWriteStream();
    var metadata = {
        contentType: mime.lookup(req.file.originalname)
    };

    blobStream.on('error', function (err) {
        return next(err);
    });

    blobStream.on('finish', function () {

        blob.setMetadata(metadata, function(err, response){
            console.log(response);
             // The public URL can be used to directly access the file via HTTP.
        var publicUrl = format(
        'https://storage.googleapis.com/%s/%s',
        bucket.name, blob.name);
        res.status(200).send(
            {
                'success': true,
                'publicUrl': publicUrl,
                'mediaLink': response.mediaLink
            });
        });

    });

    blobStream.end(req.file.buffer);

});

这似乎有效,因为它确实在上传时设置了Content-Type,并且正确反映在响应对象和云存储控制台中。问题是某些返回为publicUrl 的链接会导致文件下载,而其他链接会导致浏览器加载图像。理想情况下,我希望这两个选项都可用,但我看不到存储的文件或其元数据有任何差异。

我在这里错过了什么?

【问题讨论】:

    标签: node.js google-cloud-storage


    【解决方案1】:

    Google Cloud Storage 不对上传对象的内容类型做出任何假设。如果您不指定,GCS 将简单地分配一个类型“application/octet-stream”。

    不过,命令行工具 gsutil 更智能,并且在大多数情况下会为上传的文件附加正确的 Content-Type,包括 JPEG。

    现在,您的浏览器可能会下载图片而不是显示图片有两个原因。首先,如果 Content-Type 设置为“application/octet-stream”,大多数浏览器会将结果作为文件下载而不是显示。这很可能发生在您的案例中。

    第二个原因是服务器是否使用“Content-Disposition: attachment”标头进行响应。当您像上面所做的那样从主机“storage.googleapis.com”获取 GCS 对象时,通常不会发生这种情况,但如果您为已上传的对象明确指定了 contentDisposition,则可能发生这种情况。

    因此,我怀疑您的某些对象没有“图像/jpeg”内容类型。您可以像这样使用 gsutil 进行设置:gsutil -m setmeta 'Content-Type:image/jpeg' gs://myBucketName/**

    【讨论】:

    • 我检查并验证了所有文件都正确标记了适当的 mime 类型,并且没有一个标记为 application-octet-stream。此外,我验证了未设置“Content-Disposition”值,但只是为了矫枉过正,在服务器代码中显式添加了一行,以在元数据中将其标记为 null。一时兴起,我复制了一个. jpg 文件并将扩展名更改为.jpeg.jpeg 文件正确加载,而.jpg 版本仍在下载。完全相同的文件。但是其他带有.jpg 扩展名的人工作得很好。
    • 有趣。那是在浏览器中使用“storage.googleapis.com/bucketName/imageName.jpg”或“imageName.jpeg”的 URL?
    • 没错。我刚刚进行了另一项测试,在该测试中,我在上传的元数据中明确添加了 'Content-Disposition' 值“内联”。我删除了存储中的所有文件,并重新加载了上述两个.jpeg 变体。响应对象 Cloud Storage 控制台验证 MIME 类型和处置是否按预期设置。只有这一次,我得到了完全相反的行为。 .jpeg 文件显示在浏览器中,而 .jpg 版本下载。令人沮丧!
    • 这些是公开可读的对象,是吗?如果是这样,您可能会被缓存所困扰。默认情况下,公开可读的对象最多可以缓存一个小时(您可以通过设置对象的 cacheControl 属性或仅使用多余的额外 URL 参数发出请求来覆盖它)。
    • 我认为这就是答案。显然有一个默认的 3600 秒。这些存储桶中对象的缓存寿命。添加 cacheControl: 'no-cache' 的元数据字段对已被缓存的项目没有影响,即使在被删除和重新加载后也是如此。但是当我将 ?ignoreCache=1 的值附加到 URI 时,内容会在浏览器中正确呈现。我怀疑这在实际使用中不会出现问题,因为缓存会在一小时后重置。感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-28
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    相关资源
    最近更新 更多