我正在开展这个项目,我使用通过Google-Cloud-Endpoints连接到Android应用的Google-App-Engine后端。对于Google-Cloud-Datastore访问,我使用Objectify并且一切正常。
现在我决定添加将图片上传到Google-Cloud-Storage的功能,但我无法使用Google-Cloud-Endpoints设置找到有关如何执行此操作的明确说明。
我找到了如何将Google-Cloud-Storage与Google-App-Engine结合使用的以下说明: https://cloud.google.com/appengine/docs/java/googlecloudstorageclient/app-engine-cloud-storage-sample
但不是将其添加到Endpoints Api,而是写一篇额外的servlet。
此外,我发现了Android的上传/下载示例:
github.com / thorrism / GoogleCloudExample
可悲的是,这是使用Google云端存储API直接访问Google-Cloud-Storage,您需要将P12文件添加到资产文件夹,这似乎不安全。
我的Google-App-Engine代码如下:
@Api(
name = "example",
version = "v1",
scopes = { Constants.EMAIL_SCOPE },
clientIds = { Constants.WEB_CLIENT_ID, Constants.ANDROID_CLIENT_ID, Constants.API_EXPLORER_CLIENT_ID },
audiences = {Constants.ANDROID_AUDIENCE},
description = "API for the Example Backend application."
)
public class ExampleApi{
@ApiMethod(name = "doSomething", path = "dosomething", httpMethod = HttpMethod.POST)
public String doSomething(@Named("text") String text){
TestEntity test = new TestEntity(text);
ofy().save().entity(test).now();
return test;
}
上传后,我生成了Endpoints Client Library并将其导入到我的android项目中。
然后我就像在这里解释的那样从Android调用端点:
public static com.appspot.******.example.Example buildServiceHandler(Context context, String email) {
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience(
context, AppConstants.AUDIENCE);
credential.setSelectedAccountName(email);
com.appspot.******.example.Example.Builder builder = new com.appspot.******.example.Example.Builder(
AppConstants.HTTP_TRANSPORT,
AppConstants.JSON_FACTORY, null);
builder.setApplicationName("example-server");
return builder.build();
}
sApiServiceHandler = buildServiceHandlerWithAuth(context,email);
每个Api-Method我都这样称呼:
com.appspot.******.example.Example.DoSomething doSomething = sApiServiceHandler.doSomething(someString);
doSomething.execute();
所有这些都可以正常工作,但仅适用于存储/接收数据存储区实体。如何使用Google Cloud Endpoints设置上传/下载文件到Google云端存储? 是否有可能使用已构建的ServiceHandler将带有我的图像数据的POST通过端点发送到UploadServlet? 是否可以从端点方法调用servlet?我该如何将Post发送到Servlet以及如何进行身份验证?
非常感谢任何帮助或建议!
答案 0 :(得分:0)
有不同的方法可以执行此操作,但最常用的方法是使用Signed URLs,以便您的Android应用可以直接将文件安全地上传到Google云端存储,而无需通过您的终端后端。基本过程是:
1)创建creates a new signed URL的端点方法并将其返回给Android客户端。在服务器上签名URL仍然需要P12密钥,但存储在App Engine上,而不是客户端,因此是安全的。尝试使用URL的短暂过期,例如不超过5分钟。
2)拥有Android客户端upload the file directly to the signed URL,因为您对HTTP PUT正常Cloud Storage XML API上传文件(resumable uploads with the JSON API)也受支持,但未涵盖这里)。
您的Endpoints方法可能如下所示:
@ApiMethod(name = "getUploadUrl", path = "getuploadurl", httpMethod = HttpMethod.GET)
public MyApiResponse getUploadUrl(@Named("fileName") String fileName
@Named("contentType" String contentType)
{
String stringToSign
= "PUT\n" + contentType
+ "\n" + EXPIRATION_TIMESTAMP_EPOCH_SECONDS + "\n"
+ YOUR_GCS_BUCKET + "/" + fileName;
// Load P12 key
FileInputStream fileInputStream = new FileInputStream(PATH_TO_P12_KEY);
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(fileInputStream, password);
PrivateKey key = keyStore.getKey(privatekey", YOUR_P12_KEY_PASSWORD);
// Get signature
Signature signer = Signature.getInstance("SHA256withRSA");
signer.initSign(key);
signer.update(stringToSign.getBytes("UTF-8"));
byte[] rawSignature = signer.sign();
String signature = new String(Base64.encodeBase64(rawSignature, false), "UTF-8");
// Construct signed url
String url
= "http://storage.googleapis.com/" + YOUR_GCS_BUCKET + fileName
+ "?GoogleAccessId=" + P12_KEY_SERVICE_ACCOUNT_CLIENT_ID
+ "&Expires=" + EXPIRATION_TIMESTAMP_EPOCH_SECONDS
+ "&Signature=" + URLEncoder.encode(signature, "UTF-8");
// Endpoints doesn't let you return 'String' directly
MyApiResponse response = new MyApiResponse();
response.setString(url);
return response;
}
在Android方面,您可以使用以下方法:
// Get the upload URL from the API
getUploadUrl = sApiServiceHandler.getUploadUrl(fileName, contentType);
MyApiResponse response = getUploadUrl.execute();
String uploadUrl = response.getString();
// Open connection to GCS
URL url = new URL(uploadUrl);
HttpURLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setDoOutput(true);
httpConnection.setRequestMethod("PUT");
httpConnection.setRequestProperty("Content-Type", contentType);
// Write file data
OutputStreamWriter out = new OutputStreamWriter(httpConnection.getOutputStream());
out.write(fileData);
out.flush();
// Get response, check status code etc.
InputStreamReader in = new InputStreamReader(httpConnection.getInputStream());
// ...
(免责声明:我只是在文本编辑器中自由输入代码,但实际上没有对其进行测试,但它应该足以让您了解一般。)