首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用上传Java S3

使用上传Java S3
EN

Stack Overflow用户
提问于 2020-12-15 10:59:55
回答 3查看 1.9K关注 0票数 0

我想使用SpringBoot RestTemplate进行调用,将一个文件上传到S3桶:PutObject.html

代码语言:javascript
复制
PUT /my-image.jpg HTTP/1.1
Host: myBucket.s3.<Region>.amazonaws.com
Date: Wed, 12 Oct 2009 17:50:00 GMT
Authorization: authorization string
Content-Type: text/plain
Content-Length: 11434
x-amz-meta-author: Janet
Expect: 100-continue
[11434 bytes of object data]

代码语言:javascript
复制
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.rootUri("")
                .additionalInterceptors((request, body, execution) -> {
                    request.getHeaders().add("Authorization",
                            "Bearer a0d78d7922f333ee22d75bea53d01hhkjk83f5ac03f11ccd87787");
                    return execution.execute(request, body);
                }).build();
    }

我试过了

代码语言:javascript
复制
Resource resource = new ClassPathResource("logback.xml");
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.TEXT_PLAIN);

    HttpEntity<byte[]> requestEntity
            = new HttpEntity<>(StreamUtils.copyToByteArray(resource.getInputStream()), headers);

    Map<String, Object> parameters = new HashMap<>(4);
    parameters.put("cors_enabled", true);
    parameters.put("acl", "private");
    parameters.put("key", "my-key");
    parameters.put("Bucket", "parameters.put("Bucket", "https://cloud.linode.com/object-storage/buckets/eu-central-1/my-bucket-2020");");

    restTemplate.put("https://api.linode.com/v4/object-storage/buckets", requestEntity, parameters);

但我有

代码语言:javascript
复制
org.springframework.web.client.HttpClientErrorException$MethodNotAllowed: 405 METHOD NOT ALLOWED: [{"errors": [{"reason": "Method Not Allowed"}]}]

另外,当我得到一个问题:

代码语言:javascript
复制
MultiValueMap<String, Object> body
            = new LinkedMultiValueMap<>();

    UriComponentsBuilder builder =
            UriComponentsBuilder.fromHttpUrl("https://api.linode.com/v4/object-storage/buckets/eu-central-1/my-bucket-2020/object-url");
    builder.queryParam("method", "GET");
    builder.queryParam("name", "43f959d9-a11a-4f2cec88fd7e.JPG");

    body.add("method", "GET");
    body.add("name", "43f959d9-a11a-4f2cec88fd7e.JPG");

    HttpHeaders headers = new HttpHeaders();

    HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

    restTemplate.postForEntity(builder.build().encode().toUri(),
            requestEntity, LinodeResponse.class);

以及答复:

代码语言:javascript
复制
org.springframework.web.client.HttpClientErrorException$BadRequest: 400 BAD REQUEST: [{"errors": [{"reason": "name is required", "field": "name"}, {"reason": "method is required", "field": "method"}]}]

使用AWS访问ans时,我有以下错误:

代码语言:javascript
复制
com.amazonaws.services.s3.model.AmazonS3Exception: The AWS Access Key Id you provided does not exist in our records. 
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-12-19 16:33:25

Linode似乎提供了一个API接口来生成预先签名的urls,用于与S3中的对象交互。

要使用API,首先,您可以创建两个POJO,它们表示我们将从API发送和接收的请求和响应,这样我们就可以用来序列化反序列化JSON信息。

对于请求对象:

代码语言:javascript
复制
public class LinodeGeneratePresignedUrlRequest {
  private String method;

  private String name;

  @JsonProperty("content_type")
  private String contentType;

  @JsonProperty("expires_in")
  private int expiresIn;

  // Getters and setters
}

对于答复:

代码语言:javascript
复制
pubic class LinodeGeneratePresignedUrlResponse {

  private String url;

  // Getters and setters
}

这些对象匹配端点所需的信息。

如果您想使用Linode API在桶中创建一个对象,那么首先需要请求一个预先签名的URL。一旦获得,您将使用这个URL来执行桶对象上的实际操作。该操作由传递给API的method参数定义。请考虑以下示例:

代码语言:javascript
复制
// Obtain a reference to the RestTemplate instance.
// It should support the interchange of JSON information
RestTemplate restTemplate  = new RestTemplate();

HttpHeaders headers = new HttpHeaders();

// Set content type to the one required by the Linode API application/json
headers.setContentType(MediaType.APPLICATION_JSON);

// Set the appropriate credentials for the Linode API
String token = "your token";
headers.set(HttpHeaders.AUTHORIZATION, "Bearer" + token);

// Create the presigned url request
LinodeGeneratePresignedUrlRequest linodeGeneratePresignedUrlRequest =
  new LinodeGeneratePresignedUrlRequest();
// Operation to perform when you interact with AWS later
// In this case, PUT because you need to create a new object
linodeGeneratePresignedUrlRequest.setMethod("PUT"); 
// The object name: can match or not the actual file you want to upload
linodeGeneratePresignedUrlRequest.setName("my-object-name.pdf"); 
// As you are performing an upload (PUT, POST), indicate the content type of 
// the information you are uploading to AWS. It should match the provided later
// when you interact with AWS. For instance, consider that you are uploading a PDF file
linodeGeneratePresignedUrlRequest.setContentType("application/pdf");
// Optionally, you can set the expiration time of the generated presigned url
// By default, an hour (3600 seconds)

// Perform the actual Linode API invocation
HttpEntity<LinodeGeneratePresignedUrlRequest> requestEntity = 
  new HttpEntity<LinodeGeneratePresignedUrlRequest>(linodeGeneratePresignedUrlRequest, headers);

// The Linode API URL for your cluster and bucket
String linodeApiUrl = "https://api.linode.com/v4/object-storage/buckets/eu-central-1/my-bucket-2020/object-url";

HttpEntity<LinodeGeneratePresignedUrlResponse> responseEntity = restTemplate.exchange(linodeApiUrl, HttpMethod.POST, requestEntity, LinodeGeneratePresignedUrlResponse.class);

// Linde wil provide a response with a property named 'url' corresponding 
// to the presigned url that we can use to interact with AWS S3
LinodeGeneratePresignedUrlResponse linodeGeneratePresignedUrlResponse = responseEntity.getBody();

String signedUrl = linodeGeneratePresignedUrlResponse.getUrl();

// Now, send the actual file.
// I am following the example provided in the AWS documentation:
// https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObjectJavaSDK.html adapt for RestTemplate

HttpHeaders headersForS3 = new HttpHeaders();
// You should provide the same content type you indicated previously
headersForS3.set("Content-Type", "application/pdf");
Resource resource = new FileSystemResource("my-object-name.pdf"); 

HttpEntity<byte[]> requestEntityForS3 =
  new HttpEntity<>(
    StreamUtils.copyToByteArray(resource.getInputStream()), headersForS3);
// You should use the same HTTP verb as indicated in 
// the 'method' parameter before
restTemplate.exchange(signedUrl, HttpMethod.PUT, requestEntityForS3, Void.class);

检索创建的对象的过程非常相似:

代码语言:javascript
复制
RestTemplate restTemplate  = new RestTemplate();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

String token = "your token";
headers.set(HttpHeaders.AUTHORIZATION, "Bearer" + token);

LinodeGeneratePresignedUrlRequest linodeGeneratePresignedUrlRequest =
  new LinodeGeneratePresignedUrlRequest();
// Instead of PUT, indicate that you want to retrieve the object
linodeGeneratePresignedUrlRequest.setMethod("GET");
 // your object name
linodeGeneratePresignedUrlRequest.setName("my-object-name.pdf");

HttpEntity<LinodeGeneratePresignedUrlRequest> requestEntity = 
  new HttpEntity<LinodeGeneratePresignedUrlRequest>(linodeGeneratePresignedUrlRequest, headers);

String linodeApiUrl = "https://api.linode.com/v4/object-storage/buckets/eu-central-1/my-bucket-2020/object-url";

HttpEntity<LinodeGeneratePresignedUrlResponse> responseEntity = restTemplate.exchange(linodeApiUrl, HttpMethod.POST, requestEntity, LinodeGeneratePresignedUrlResponse.class);

LinodeGeneratePresignedUrlResponse linodeGeneratePresignedUrlResponse = responseEntity.getBody();

String signedUrl = linodeGeneratePresignedUrlResponse.getUrl();

// Read the object from your bucket
byte[] objectBytes = restTemplate.getForObject(signedUrl, byte[].class);
// And use the information as you need
Files.write(Paths.get("my-object-name.pdf"), objectBytes);

当然,如果Linode为您提供了适当的凭据,您也可以使用AWS直接与S3交互。

票数 0
EN

Stack Overflow用户

发布于 2020-12-15 18:48:08

与您提供的cURL命令等效的Spring可以是:

代码语言:javascript
复制
RestTemplate restTemplate  = new RestTemplate();

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String token = "";
headers.set(HttpHeaders.AUTHORIZATION, token);

JSONObject data = new JSONObject();
data.put("cors_enabled", true);
data.put("acl", "private");

HttpEntity<String> requestEntity = new HttpEntity<String>(data.toString(), headers);

String url = "https://api.linode.com/v4/object-storage/buckets/eu-central-1/bonansa15122020/access";
HttpEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.PUT, requestEntity, String.class);

在第一个示例中,您还没有提供授权头,所以您将得到401响应。您没有使用您在这里使用RestTemplate创建的RestTemplateBuilder

在您的第二个示例中,请求体似乎不是JSON (您正在读取logback文件,因此其中不太可能有JSON )。看来Linode API需要一个JSON主体。

票数 0
EN

Stack Overflow用户

发布于 2020-12-17 11:47:24

更新

我相信您可以使用PUT请求作为端点https://api.linode.com/v4/object-storage/buckets/{clusterId}/{bucket}/object-url的POST请求的一部分。

这里有更多的细节- https://developers-linode.netlify.app/api/v4/object-storage-buckets-cluster-id-bucket-object-url#post

我无法进行测试,因为我没有linode的帐户。

我认为另一个可行的解决方案是为s3使用aws将文件上传到linode端点。

下面是一个简单的例子- code/s3/src/main/java/aws/example/s3/PutObject.java

原版:

基于linode文档,该方法应该是post

https://www.linode.com/docs/api/object-storage/#object-storage-bucket-create

代码语言:javascript
复制
restTemplate.post("https://api.linode.com/v4/object-storage/buckets", requestEntity, parameters)

此外,请检查请求机构,以符合文件。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65304541

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档