Amazon AWS错误,S3存储桶不存在(Spring Boot)

huangapple go评论69阅读模式
英文:

Amazon aws error with s3 bucket not existing (Spring Boot)

问题

I'm developing a product registration api in spring boot, and in my post method I send an image upload via multipart/form-data, along with a json with my product's dto. As you can see:

@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
@RequestMapping("/product")
public class ProductController {
    final ProductService productService;
    final CategoryService categoryService;
    final ProductMapper productMapper;
    final S3Client s3Client;

    private final String BUCKET_NAME = "awstockproducts" + System.currentTimeMillis();

    public ProductController(ProductService productService, ProductMapper productMapper, CategoryService categoryService, S3Client s3Client) {
        this.productService = productService;
        this.productMapper = productMapper;
        this.categoryService = categoryService;
        this.s3Client = s3Client;
    }
    @PostMapping(value = "/", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<Object> saveProduct (@RequestParam("productDto") String jsonString, @RequestParam("file")MultipartFile file) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            ProductDto productDto = objectMapper.readValue(jsonString, ProductDto.class);

            if (productService existsByProduct(productDto.getProduct())) {
                return ResponseEntity.status(HttpStatus.CONFLICT).body("Product already exists!");
            }
            ProductModel productModel = productMapper.toProductModel(productDto);
            CategoryModel categoryModel = categoryService.findById(productDto.getProductCategory().getCategory_id())
                    .orElseThrow(() -> new RuntimeException("Category not found"));
            productModel.setProductCategory(categoryModel);

            String fileName = "/products/images/" + UUID.randomUUID().toString() + "-" + file.getOriginalFilename();

            s3Client.putObject(PutObjectRequest
                            .builder()
                            .bucket(BUCKET_NAME)
                            .key(fileName)
                            .build(),
                        software.amazon.awssdk.core.sync.RequestBody.fromString("Testing java sdk"));
            return ResponseEntity.status(HttpStatus.CREATED).body(productService.save(productModel));
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.CONFLICT).body(e);
        }
    }
}

The problem is that I am having problems making the request from my postman:

"localizedMessage": "The specified bucket does not exist (Service: S3, Status Code: 404, Request ID: ZZ27F9CNNTG2RTPR, Extended Request ID: 

Despite the message, checking Amazon AWS, I can see that indeed my bucket exists and has the same name as the one I configured in my application. This is AmazonConfig:

package com.api.business_manager_api.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

@Configuration
public class AmazonConfig {
    private final String AWS_REGION = "us-east-1";
    private final String BUCKET_NAME = "productstockimages";

    @Value("${aws.accessKeyId}")
    private String accessKeyId;

    @Value("${aws.secretAccessKey}")
    private String secretAccessKey;

    @Bean
    public S3Client s3Client() {
        AwsBasicCredentials awsCreds = AwsBasicCredentials.create(accessKeyId, secretAccessKey);
        return S3Client.builder()
                .region(Region.of(AWS_REGION))
                .credentialsProvider(StaticCredentialsProvider.create(awsCreds))
                .build();
    }
}

In my secret key and in my access key, I configured in properties with the keys of my authorized IAM user from the Amazon AWS console.

英文:

I'm developing a product registration api in spring boot, and in my post method I send an image upload via multipart/form-data, along with a json with my product's dto. As you can see:

@RestController
@CrossOrigin(origins = &quot;*&quot;, maxAge = 3600)
@RequestMapping(&quot;/product&quot;)
public class ProductController {
final ProductService productService;
final CategoryService categoryService;
final ProductMapper productMapper;
final S3Client s3Client;
private final String BUCKET_NAME = &quot;awstockproducts&quot; + System.currentTimeMillis();
public ProductController(ProductService productService, ProductMapper productMapper, CategoryService categoryService, S3Client s3Client) {
this.productService = productService;
this.productMapper = productMapper;
this.categoryService = categoryService;
this.s3Client = s3Client;
}
@PostMapping(value = &quot;/&quot;, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity&lt;Object&gt; saveProduct (@RequestParam(&quot;productDto&quot;) String jsonString, @RequestParam(&quot;file&quot;)MultipartFile file) {
try {
ObjectMapper objectMapper = new ObjectMapper();
ProductDto productDto = objectMapper.readValue(jsonString, ProductDto.class);
if (productService.existsByProduct(productDto.getProduct())) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(&quot;Product already exists!&quot;);
}
ProductModel productModel = productMapper.toProductModel(productDto);
CategoryModel categoryModel = categoryService.findById(productDto.getProductCategory().getCategory_id())
.orElseThrow(() -&gt; new RuntimeException(&quot;Category not found&quot;));
productModel.setProductCategory(categoryModel);
String fileName = &quot;/products/images/&quot; + UUID.randomUUID().toString() + &quot;-&quot; + file.getOriginalFilename();
s3Client.putObject(PutObjectRequest
.builder()
.bucket(BUCKET_NAME)
.key(fileName)
.build(),
software.amazon.awssdk.core.sync.RequestBody.fromString(&quot;Testing java sdk&quot;));
return ResponseEntity.status(HttpStatus.CREATED).body(productService.save(productModel));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.CONFLICT).body(e);
}
}

The problem is that I am having problems making the request from my postman

    &quot;localizedMessage&quot;: &quot;The specified bucket does not exist (Service: S3, Status Code: 404, Request ID: ZZ27F9CNNTG2RTPR, Extended Request ID: 

Despite the message, checking amazon aws I can see that indeed my bucket exists and has the same name as the one I configured in my application. This is amazonConfig

package com.api.business_manager_api.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
@Configuration
public class AmazonConfig {
private final String AWS_REGION = &quot;us-east-1&quot;;
private final String BUCKET_NAME = &quot;productstockimages&quot;;
@Value(&quot;${aws.accessKeyId}&quot;)
private String accessKeyId;
@Value(&quot;${aws.secretAccessKey}&quot;)
private String secretAccessKey;
@Bean
public S3Client s3Client() {
AwsBasicCredentials awsCreds = AwsBasicCredentials.create(accessKeyId, secretAccessKey);
return S3Client.builder()
.region(Region.of(AWS_REGION))
.credentialsProvider(StaticCredentialsProvider.create(awsCreds))
.build();
}
}

In my secretKey and in my AccessKey, I configured in properties with the keys of my authorized IAM user from the amazon aws console.

答案1

得分: 1

上面的回答提到了AWS SDK for Java V1,不建议再使用。查看版本信息,请参考SDK页面:

https://github.com/awsdocs/aws-doc-sdk-examples

不要再查看包含V1代码的AWS S3服务指南,现在请参考AWS代码库,它使用最新的SDK版本 - 对于Java来说,是AWS SDK for Java V2。

Amazon AWS错误,S3存储桶不存在(Spring Boot)

有关AWS SDK for Java V2的示例,请参见:

使用AWS SDK的Amazon S3代码示例

我在许多Spring Boot项目中使用了V2,没有与S3操作的问题。因此,在Spring Boot中使用S3 Java功能,建议升级到V2 - 这是最佳实践。

可能存在的问题更新

我正在仔细查看您的代码。我在您的控制器中看到这个问题:

private final String BUCKET_NAME = "awstockproducts" + System.currentTimeMillis();

您正在使用时间戳更改桶的名称。然后您调用**putObject()**并引用具有时间戳的桶名称。除非您通过这个名称即时创建了一个桶(我没有看到这个逻辑),否则该桶不存在,您会收到异常。

因此,您有两种选择:

  • 保持桶名称不变,以便您知道它存在。
  • 或者如果必须使用时间戳来创建一个桶,那么使用V2 API和一个等待器在调用**putObject()**之前创建一个桶。然后,您可以引用具有时间戳的桶名称。要了解如何使用V2创建一个新桶并使用等待器,请参阅此处的创建桶示例。注意等待器的使用。这种方法将为每个请求创建一个新的桶。我个人建议使用静态桶名称。

https://docs.aws.amazon.com/code-library/latest/ug/java_2_s3_code_examples.html

英文:

The answer above references AWS SDK for Java V1 - which is not recommended to use anymore. See the SDK page here for Version information:

https://github.com/awsdocs/aws-doc-sdk-examples

Rather then looking into the AWS S3 Service Guide that contains V1 code, now refer to the AWS Code Library that uses the latest SDK version - which for Java is AWS SDK for Java V2.

Amazon AWS错误,S3存储桶不存在(Spring Boot)

For AWS SDK for Java V2 examples, see:

Code examples for Amazon S3 using AWS SDKs

I have used V2 in many Spring Boot projects and there are no issues working with S3 operations. So to use S3 Java functionality in Spring boot, upgrade to V2 - which is best practice.

UPDATE ON A POSSIBLE ISSUE

I am looking at your code much closer. I see this issue in your controller:

private final String BUCKET_NAME = "awstockproducts" + System.currentTimeMillis();

You are changing your bucket name with a time stamp. Then you call putObject() and reference that bucket name with a timestamp. Unless you created a bucket on the fly with that name (and I do not see that logic), that bucket does not exist and you get an exception.

SO you have 2 choices:

  • keep the bucket name static so you know it exists.
  • or if you have to keep a timestamp for a bucket, then use the V2 API and a waiter to create a bucket before calling putObject(). Then you can reference the bucket name with the timestamp. To learn how to create a new bucket with a waiter using V2, see the Create Bucket example here. Notice the user of a waiter. This approach will create a new bucket for each request. I personally would use a static bucket name.

https://docs.aws.amazon.com/code-library/latest/ug/java_2_s3_code_examples.html

答案2

得分: 0

为将您的数据(照片、视频、文档等)上传到Amazon S3,您首先必须在AWS的一个区域中创建一个S3存储桶,存储桶是Amazon S3中存储对象的容器。

您需要确保您要使用的存储桶已经存在

在上传文件到S3之前,请使用以下条件确保存储桶已经存在:

if (s3Client.doesBucketExist(bucketName)) {
    ObjectMetadata metadata = new ObjectMetadata();
    metadata.setContentType(contentType);
    metadata.setContentLength(stream.available());

    s3Client.putObject(new PutObjectRequest(bucketName, key, stream, metadata));
} else {
    log.warn("AWS S3 '{}' 存储桶不存在", bucketName);
    s3client.createBucket(bucketName);
}

如果 s3client.createBucket(bucketName); 抛出异常,那意味着您没有权限创建一个存储桶,请使用此文档创建一个:https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html

如果您根本没有权限,请与您的AWS管理员联系以为您创建一个。

此外,不要每次都像这样创建一个存储桶:

private final String BUCKET_NAME = "awstockproducts" + System.currentTimeMillis();

只需为不同类型的应用程序使用一个存储桶:

private final String BUCKET_NAME = "awstockproducts-app1-dev";

这样您不会在每次运行应用程序时都创建一个存储桶
英文:

To upload your data (photos, videos, documents, etc.) to Amazon S3, you must first create an S3 bucket in one of the AWS Regions, a bucket is a container for objects stored in Amazon S3.

You need to make sure the bucket you're using already exists

use this condition to make sure the bucket already exists before uploading a file to S3:

if (s3Client.doesBucketExist(bucketName)) {
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentType(contentType);
metadata.setContentLength(stream.available());
s3Client.putObject(new PutObjectRequest(bucketName, key, stream, metadata));
} else {
log.warn(&quot;AWS S3 &#39;{}&#39; Bucket does not exist&quot;, bucketName);
s3client.createBucket(bucketName);
}

if s3client.createBucket(bucketName); throws an exception that means you're not allowed to create a bucket use this documentation to create one https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html

If you don't have access at all, you need to talk to your AWS admin to create one for you.

Also don't create a bucket each time like this

private final String BUCKET_NAME = &quot;awstockproducts&quot; + System.currentTimeMillis();

just use one for different kind of APP

private final String BUCKET_NAME = &quot;awstockproducts-app1-dev&quot;

so you don't create a bucket each time you run the application

huangapple
  • 本文由 发表于 2023年3月7日 01:17:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/75653867.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定