我正在尝试使用以下代码从Google Cloud生成下载和上传链接,以查看和上传文件:
public class Test {
public static void main(String[] args) throws IOException {
Storage storage = StorageOptions.newBuilder().setCredentials(
ServiceAccountCredentials.fromStream(new FileInputStream("C:/cred/Key.json")))
.build()
.getService();
String filePath = "file/path/";
File file = new File(filePath);
byte[] bytes = Utilities.fileToByteArray(file);
String mimeType = Utilities.getMimeType(bytes);
BlobId blobId = BlobId.of("bucket", file.getName());
BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType(mimeType).build();
URL urlGet = storage
.signUrl(BlobInfo.newBuilder("bucket", "object").build(), 1, TimeUnit.HOURS,
SignUrlOption.httpMethod(HttpMethod.GET));
URL urlPut = storage
.signUrl(blobInfo, 1, TimeUnit.DAYS, SignUrlOption.httpMethod(HttpMethod.PUT),
SignUrlOption.withContentType());
System.out.println(urlGet);
System.out.println(urlPut);
}
}
urlGet
包含下载链接,而urlPut
包含上传链接。运行该程序时,得到以下输出:
https://storage.googleapis.com/roshanbucket/jasperviewpdf?GoogleAccessId=myservice@deft-idiom-234709.iam.gserviceaccount.com&Expires=1552986620&Signature=OZl6M4uMkigu6JBMYoDumgs8P4EC%2BtcK44zHMPkG2xzq3hFfsrj8YYRRtajI8diz64vdCX54nct3wuEpXNRwcnzCmq4KdD53%2B8gbERNuttm8K6%2BlZDLGF3wng%2BCSMzghbGbLnYaZRiZbvjCG%2B3ObBUg9ZiY0qRlif9nyGFftsGUF9GGHvHP6HWP51DJOAurGytSjf9SA5HKPOw4e%2B%2BP1LltfI7m3WjWhxwnSYz4lVxcR4eksec7ILTi66jnwu1gxXtqp75XTxLp9vQa6RC4dCPGoTridFQcMqm89TVzf58c8krk7apQCR6TWp2tAWuFr2xJ1U5FwFfiBaoSX4A33rw%3D%3D
https://storage.googleapis.com/roshanbucket/pi.jpg?GoogleAccessId=myservice@deft-idiom-234709.iam.gserviceaccount.com&Expires=1553069420&Signature=YHsGTgXIBum9t5M7U%2F9fdibDvzBKttQGh0jxzbYgJkevQbpOh8gRQYOlHdjT86byobDE5TNEGF5VrGFAtI5rhRGxLw0xqcNT%2BYGfvHxAIfAJXy5ormXxWVnVEnwGMafyVLOtdIY4asa0niFu%2B36eaIqtD5UzsjUY%2F18OW%2FwvjfQmhlmsvJ7qSkfD1Oif5Rv6c%2F67z1zT7gz7rB4gTCG6mLALuRrOIwCPO%2BkyzOxP9PhEJkoB7j446v%2BhE%2F0pt0wM2nJ29%2BK3HRUShhccJzzZ%2BZRxgOXeUL44CsnYlssaTThU%2FztyUbsXWXbs2hroTcFxVVtOp7aGeCUs1qjdJkXaEg%3D%3D
当我单击第一个链接(即下载)时,它将毫无问题地呈现存储桶中的文件,但是当我使用第二个链接通过HTTP PUT和Postman将文件从计算机上载到Google Cloud时,它给了我Status 403
以下错误:
<?xml version='1.0' encoding='UTF-8'?>
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature
you provided. Check your Google secret key and signing method.</Message>
<StringToSign>PUT
multipart/form-data; boundary=-------------------------
-025804137217704409263172
1553069420
/roshanbucket/pi.jpg</StringToSign>
</Error>
我不知道是什么原因造成的。一些帮助将不胜感激。
答案 0 :(得分:0)
经过一段时间的努力,终于设法使其运行。事实证明,首先我需要生成一个签名的URL,等效于
gsutil signurl -c 'Content-Type' \
-m RESUMABLE /path/to/your/json_cert_file.json \
gs://your_bucket/file.txt
然后使用该签名的URL,发送带有Content-Type
和x-goog-resumable:start
标头(等同于
curl -v -X 'POST' \
-H 'content-type: text/plain' \
-H 'x-goog-resumable:start' \
-d '' '<signedURL>'
成功的POST将返回状态201
和Location
标头,以及您可以使用HTTP PUT
上传文件的实际位置。
下面是我在此article
的帮助下完成的Java类 import com.google.api.client.util.Base64;
import com.google.auth.oauth2.ServiceAccountCredentials;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.ResponseProcessingException;
import javax.ws.rs.core.Response;
import uploader.Utilities;
public class Uploader {
private ServiceAccountCredentials creds; // Service Account Credentials
private String saEmail; // Service Account email
public Uploader() {
/* Initialize credentials and service account email*/
try (InputStream inputStream = new FileInputStream("C:/cred/Key.json")) {
this.creds = ServiceAccountCredentials.fromStream(
inputStream);
} catch (IOException e) {
e.printStackTrace();
}
this.saEmail = "service account email";
}
/* Sign and return the URL for POST, using credentials from above*/
private String getSignedUrl(String bucketName, String objectName, String mimeType) {
String signed_url = null;
try {
String verb = "POST";
long expiration = System.currentTimeMillis() / 1000 + 60;
String Canonicalized_Extension_Headers = "x-goog-resumable:start";
String content_type = mimeType;
byte[] sr = creds.sign(
(verb + "\n\n" + content_type + "\n" + expiration + "\n" + Canonicalized_Extension_Headers
+
"\n" + "/" + bucketName + "/" + objectName).getBytes());
String url_signature = new String(Base64.encodeBase64(sr));
signed_url = "https://storage.googleapis.com/" + bucketName + "/" + objectName +
"?GoogleAccessId=" + saEmail +
"&Expires=" + expiration +
"&Signature=" + URLEncoder.encode(url_signature, "UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
}
return signed_url;
}
/* Send POST request to the signed URL using custom headers and an empty body, which returns the actual upload location */
public String getLocation(String bucketName, String objectName, String mimeType)
throws IOException {
URL myURL = new URL(getSignedUrl(bucketName, objectName, mimeType));
HttpURLConnection myURLConnection = (HttpURLConnection) myURL.openConnection();
myURLConnection.setRequestMethod("POST");
myURLConnection.setRequestProperty("Content-Type", mimeType);
myURLConnection.setRequestProperty("x-goog-resumable", "start");
// Send post request
myURLConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(myURLConnection.getOutputStream());
wr.flush();
wr.close();
int responseCode = myURLConnection.getResponseCode();
if (responseCode != 201) {
System.out.println("Request Failed");
}
return myURLConnection.getHeaderField("Location");
}
/* Do the actual upload and return the PUT Response*/
public Response doUpload(String url, InputStream inputStream, String mimeType) {
Response response = null;
Client client = ClientBuilder.newClient();
try {
response = client.target(url)
.request()
.put(Entity.entity(inputStream, mimeType));
if (response.getStatus() != 200) {
System.out.println("Request failed with " + response.getStatus());
}
} catch (ResponseProcessingException e) {
e.printStackTrace();
}
return response;
}
}
现在,只需在main
方法中调用它
public static void main(String[] args) throws Exception {
Uploader uploader = new Uploader();
String filePath = "file/path";
File file = new File(filePath);
byte[] bytes = Utilities.fileToByteArray(file); // convert file to bytes
String mimeType = Utilities.getMimeType(bytes); // bytes from above used with tika
String url = uploader.getLocation("bucket", file.getName(), mimeType);
Response r = uploader.doUpload(url, new FileInputStream(file), mimeType);
System.out.println("Response : " + r.getStatus());
System.out.println(r.getHeaders());
}
希望这对某人有帮助!此方法不需要在POST
中向Jwt
发送Authorization Bearer
请求。
答案 1 :(得分:0)
如果您使用的是SpringBoot和RestTemplate,则应该可以使用:
// IMPORTS
import org.springframework.web.client.RestTemplate;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import java.io.File;
...
// USE THIS TO UPLOAD YOUR FILE
String signedurl = "https://storage.googleapis.com/..."; // Your signed URL
File file = new File(); // Your file
FileSystemResource resource = new FileSystemResource(file);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "plain/text"); // Should be the same MediaType used to create the signedUrl
HttpEntity<FileSystemResource> requestEntity = new HttpEntity<>(resource, headers);
restTemplate.exchange(signedUrl, HttpMethod.PUT, requestEntity, String.class); // PUT is the HTTP method used to create the signedUrl
...