使用Java在谷歌云存储上使用*签名的url*进行*可恢复的上传*

Jon*_*ter 1 google-api google-cloud-storage google-cloud-platform

基于关于如何在 google-cloud-storage 中创建对象的文档(参见https://googleapis.github.io/google-cloud-java/google-cloud-clients/apidocs/index.html 中的“创建”方法),我们应该在尝试上传大文件时使用 blob.writer(...) 方法,因为它可能以某种方式自动处理可恢复的上传。这是正确的吗?

但是,如果我们希望在 SIGNED url 上进行可恢复的上传,那么在 Java 中如何实现呢?(非常感谢任何示例代码或指针;到目前为止,我的研究使我相信使用精心创建的 java 库是不可能的,而是需要使用“PUT”和“自定义构建自己的逻辑” POST”语句生成签名后的 url。这是迄今为止的“最佳”方式吗?)

Joa*_*oël 5

关于您的第一点,是的,该blob.writer(...)方法确实会自动处理可恢复的上传。不幸的是,此方法不能从签名 URL 调用,只能直接从字节流上传文件。

但是,正如您所提到的,可以使用其他方法从签名 URL 创建可恢复的上传,例如使用一种PUT方法似乎是一个不错的解决方法。

我所做的是以下内容:

  1. 使用“PUT”方法创建签名 URL。您可以通过指定SignUrlOption实现,我还指定了一个在存储桶中具有所需权限的服务帐户。

  2. 使用URLFetch向此签名 URL 发出 HTTP 请求。例如,我相信您不能直接使用 curl 命令,而 UrlFetch API 可以解决问题。

  3. 将 uploadType=resumable 标头添加到urlFetchHTTP 请求。请参阅此文档以了解其工作原理以及额外的参数和信息。

  4. 我配置URLFetch为对签名 URL 进行异步调用,因为我认为上传大文件时更方便。

要在 App Engine 处理程序中使用的示例代码:

package com.example.storage;

import java.io.IOException;
import java.io.FileInputStream;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.HashMap;
import java.util.Map;
import java.nio.charset.StandardCharsets;

import java.net.URL;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// Cloud Storage Imports
import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.BucketInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage.SignUrlOption;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.storage.HttpMethod;

// Url Fetch imports
import com.google.appengine.api.urlfetch.HTTPMethod;
import com.google.appengine.api.urlfetch.HTTPRequest;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.urlfetch.URLFetchServiceFactory;
import com.google.appengine.api.urlfetch.HTTPHeader;

@WebServlet(name = "MainStorage", value = "/")
public class MainStorage extends HttpServlet {

        @Override
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
                // Bucket parameters 
                String bucketName = "MY-BUCKET-NAME";
                String blobName = "MY-BLOB-NAME";
                String keyPath = "/PATH-TO-SERVICE-ACCOUNT-KEY/key.json";

                BlobId blobId = BlobId.of(bucketName, blobName);
                Storage storage = StorageOptions.getDefaultInstance().getService();

                // Create signed URL with SignUrlOptions
                URL signedUrl = storage.signUrl(BlobInfo.newBuilder(bucketName, blobName).build(), 14, TimeUnit.DAYS,
                                                SignUrlOption.signWith(ServiceAccountCredentials.fromStream(new FileInputStream(keyPath))),
                                                SignUrlOption.httpMethod(HttpMethod.PUT));

                // Contents to upload to the Blob
                String content = "My-File-contents";

                // Build UrlFetch request
                HTTPRequest upload_request = new HTTPRequest(signedUrl, HTTPMethod.PUT);
                upload_request.setPayload(content.getBytes(StandardCharsets.UTF_8));

                // Set request to have an uploadType=resumable
                HTTPHeader set_resumable = new HTTPHeader("uploadType", "resumable");
                upload_request.setHeader(set_resumable);
                URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService();

                // Do an asynchronous call to the signed URL with the contents
                fetcher.fetchAsync(upload_request);

                // Return response to App Engine handler call
                response.setContentType("text/plain");
                response.getWriter().println("Hello Storage");
        }
}
Run Code Online (Sandbox Code Playgroud)

这可能可以以更好的方式完成,但我相信它提供了如何制作此类应用程序的想法。