无法通过我的Azure REST API将图像文件上传到我的AWS S3存储桶

brqmpdu1  于 2023-06-24  发布在  其他
关注(0)|答案(1)|浏览(83)

我的项目设置如下:
前端- TypeScript,React,fetch()用于调用我的后端API,而不是axios。
后端- C#、ASP.NET Core、Swagger UI、Azure
我正在尝试通过部署在Azure上的我自己的API后端实现一个简单的图像文件上传功能到我的S3存储桶。当我用Swagger UI测试 just 用于上传的API端点时,它可以正常工作,没有任何问题。但是,当我尝试使用fetch()从前端调用同一个端点时,我得到以下错误:

ImageUploadFunction.tsx:33     POST https://project.azurewebsites.net/api/files/upload 500 (Internal Server Error)

**后台代码:**FilesController.cs

using System.Threading.Tasks;
using Amazon.S3;
using Amazon.S3.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System;
using System.Linq;
using API.Model;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;

namespace API.Controllers
{
    [Route("api/files")]
    [ApiController]
    public class FilesController : BaseApiController
    {
        private readonly IAmazonS3 _s3Client;
        private readonly IOptions<AWSSecretsModel> awsSettings;
        private readonly IConfiguration _config;

        public FilesController(IAmazonS3 s3Client, IOptions<AWSSecretsModel> aws, IConfiguration config)
        {
            _s3Client = s3Client;
            awsSettings = aws;
            _config = config;
        }

        [HttpPost("upload")]
        public async Task<IActionResult> UploadFileAsync(IFormFile file)
        {
            if (file is null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            try 
            {
                var awsBucketName = awsSettings.Value.AWS_S3_BUCKET;
                var awsRegion = awsSettings.Value.AWS_REGION;

                // Upload the raw image to S3
                var bucketExists = await _s3Client.DoesS3BucketExistAsync(awsBucketName);
                if (!bucketExists) return NotFound($"Bucket {awsBucketName} does not exist.");

                var fileNameToPrefix = file.FileName;

                var request = new PutObjectRequest
                {
                    BucketName = awsBucketName,
                    Key = fileNameToPrefix,
                    InputStream = file.OpenReadStream()
                };
                await _s3Client.PutObjectAsync(request);

                return Ok($"File {file.FileName} [{fileNameToPrefix}] uploaded to S3 successfully!");
            }
            catch (ArgumentNullException ex)
            {
                return BadRequest(ex.Message);
            }
            catch (AmazonS3Exception ex)
            {
                return BadRequest($"Error uploading to S3: {ex.Message}");
            }
            catch (Exception ex)
            {
                return BadRequest($"Error: {ex.Message}");
            }
        }
    }
}

**前端:**ImageUploadFunction.tsx

import { useState, useEffect, ChangeEvent } from "react";

const API_URL = process.env.REACT_APP_API_URL;
const UPLOAD_URL = API_URL + `/api/files/upload`;

const ImageUpload: React.FC = () => {
    const [selectedImage, setSelectedImage] = useState<File | null>(null);
    const [uploading, setUploading] = useState(false);

    const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
        const files = event.target.files;
        if (files && files.length > 0) {
            setSelectedImage(files[0]);
        }
    };

    const handleImageUpload = async () => {
        if (!selectedImage) return;

        try {
            setUploading(true);

            const formData = new FormData();
            formData.append('file', selectedImage);

            const response = await fetch(UPLOAD_URL, {
                method: 'POST',
                body: formData,
            });

            if (response.ok) {
                console.log('Image uploaded successfully!');
            } else {
                console.error('Image upload failed!');
            }
        } catch (error) {
            console.error('Error uploading image:', error);
        } finally {
            setUploading(false);
        }
    };

    return (
        <div>
            <input type="file" onChange={handleFileChange} />
            <button onClick={handleImageUpload} disabled={!selectedImage || uploading}>
                {uploading ? 'Uploading...' : 'Upload Image'}
            </button>
        </div>
    );
};

export default ImageUpload;

由于通过Swagger和Postman一切正常,我觉得这个问题与我的前端有关,尽管有错误消息。我只是不知道我做错了什么。
有什么建议吗?

编辑:

我刚刚注意到,我只能通过localhost成功上传图像文件,当我在其开发环境中运行我的后端时(https://localhost:5001/api/files/upload)。尝试通过我的实时应用URL(https://project.azurewebsites.net/api/files/upload)进行POST调用时,我遇到了500内部服务器错误。所以我的问题肯定在于我的Azure配置,对吗?

编辑2:

下面是我的存储桶策略以及我的S3存储桶的CORS配置。
Bucket策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicRead",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::mys3bucketname/*"
        }
    ]
}

CORS配置:

[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "GET",
            "PUT",
            "POST",
            "HEAD"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": []
    }
]

**编辑3:**根据注解中的建议,在后端代码(FilesController.cs)中添加了异常处理。

zmeyuzjn

zmeyuzjn1#

这并不是真正解决实际问题的解决方案,但我决定改用AWS Elastic Beanstocks,因为我所有的其他服务都由AWS托管。我已经可以透露,在直接将后端部署到EBS后,我的上传端点工作起来就像一个魅力。
然而,正如Derpirscher和Marc Campora所指出的,在端点中提供异常处理来显示可能发生的事情可以(老实说应该)指出正确的方向。在我的情况下,虽然,这并没有帮助我任何进一步,所以我只是决定咬紧牙关,离开Azure。
我仍然保留所有与Azure相关的代码,所以我很乐意将这个问题留给其他任何人来提出建议/解决方案,我会尝试实现它们。以防万一其他人也会偶然发现这个问题。

相关问题