基于有关如何在google-cloud-storage中创建对象的文档(请参见https://googleapis.github.io/google-cloud-java/google-cloud-clients/apidocs/index.html中的“ create”方法),我们在尝试执行时应使用blob.writer(...)方法上传大文件,因为它大概会以某种方式自动处理可恢复的上传。是这样吗?
但是,如果我们希望在SIGNED网址上进行可恢复的上传,那么在Java中如何做到这一点? (非常感谢任何示例代码或指针;到目前为止,我的研究使我相信,无法使用精美创建的Java库,而是需要使用“ PUT”和“ Java中的POST”语句生成了签名的URL。到目前为止,这是“最佳”方法吗?)
答案 0 :(得分:3)
关于您的第一点,是的,blob.writer(...)
方法会自动处理可恢复的上传。不幸的是,该方法无法从已签名的URL调用,只能直接从字节流中上传文件。
但是,正如您提到的,可以使用其他方法从签名的URL创建可恢复的上载,例如,使用PUT
方法似乎是一个不错的解决方法。
我所做的是:
使用“ PUT”方法创建signed URL。您可以通过指定SignUrlOption以及我在存储桶中指定了具有所需权限的服务帐户来实现。
使用URLFetch向该签名的URL发出HTTP请求。我相信例如您不能直接使用curl命令,而UrlFetch API可以解决问题。
将uploadType = resumable标头添加到urlFetch
HTTP请求中。有关其工作原理,请参见this documentation,以及更多的参数和信息。
我将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");
}
}
这也许可以用更好的方法来完成,但是我相信它为如何制作这样的应用提供了一个思路。