You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React通过API Gateway上传图片到S3失败,求解决方案

React通过API Gateway上传图片到S3的解决建议

问题背景

已有Node.js代码可通过API Gateway将图片上传至S3,但文件路径为硬编码;参考教程编写的React前端代码无法实现上传,需实现从前端选择图片并通过PUT请求上传的功能。

可行的Node.js代码分析

Node.js代码通过form-data构造表单数据,将文件流添加到表单中,同时设置正确的请求头(包含Content-Type和FormData自动生成的头部),最终通过PUT请求完成上传:

const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs-extra');
let data = new FormData();
data.append('filename', fs.createReadStream('/Users/hp/Downloads/IMG_0733.jpg'));

let config = {
  method: 'put',
  url: 'https://XXXXX.execute-api.us-east-1.amazonaws.com/prod/XXXXX/IMG_0733.jpg',
  headers: { 
    'Content-Type': 'image/jpeg', 
    ...data.getHeaders()
  },
  data : data
};

axios(config)
.then((response) => {
  console.log(JSON.stringify(response.data));
})
.catch((error) => {
  console.log(error);
});

React代码的问题

原React代码存在以下关键问题:

  • 使用占位符<file contents here>,未实际使用选中的文件对象
  • 手动设置Content-Type但未处理FormData的请求头,与Node.js的请求格式不匹配
  • 未正确构造FormData来传递文件内容

修复后的React代码

以下是修正后的Class组件代码,完全对齐Node.js的请求逻辑:

import axios from 'axios';
import React, { Component } from 'react';

class Upload extends Component {
  state = {
    selectedFile: null
  };

  onFileChange = event => {
    this.setState({ selectedFile: event.target.files[0] });
  };

  onFileUpload = async () => {
    const { selectedFile } = this.state;
    if (!selectedFile) return;

    // 构造FormData,和Node.js逻辑一致
    const formData = new FormData();
    formData.append('filename', selectedFile);

    try {
      const response = await axios.put(
        // 动态替换URL中的文件名
        `https://XXX.execute-api.us-east-1.amazonaws.com/prod/XXXX/${selectedFile.name}`,
        formData,
        {
          headers: {
            'Content-Type': selectedFile.type,
            ...formData.getHeaders()
          }
        }
      );
      console.log('上传成功:', response.data);
    } catch (error) {
      console.error('上传失败:', error.response?.data || error.message);
    }
  };

  fileData = () => {
    if (this.state.selectedFile) {
      return (
        <div>
          <h2>File Details:</h2>
          <p>File Name: {this.state.selectedFile.name}</p>
          <p>File Type: {this.state.selectedFile.type}</p>
          <p>
            Last Modified:{" "}
            {this.state.selectedFile.lastModifiedDate.toDateString()}
          </p>
        </div>
      );
    } else {
      return (
        <div>
          <br />
          <h4>Choose before Pressing the Upload button</h4>
        </div>
      );
    }
  };

  render() {
    return (
      <div>
        <h3>File Upload using React!</h3>
        <div>
          <input type="file" accept="image/*" onChange={this.onFileChange} />
          <button onClick={this.onFileUpload}>Upload!</button>
        </div>
        {this.fileData()}
      </div>
    );
  }
}

export default Upload;

关键修复点说明

  1. 使用选中的文件对象:直接将event.target.files[0]添加到FormData中,替代占位符
  2. 动态URL文件名:根据选中文件的名称动态拼接请求URL,避免硬编码
  3. 对齐请求头:复用Node.js的请求头逻辑,同时设置文件的实际MIME类型和FormData自动生成的头部
  4. 错误处理优化:使用async/await简化异步逻辑,同时捕获并输出更详细的错误信息

额外注意事项

  • 确保API Gateway的PUT端点配置支持接收FormData格式的请求,且权限设置正确(允许前端域名的CORS请求)
  • 如果S3路径需要特定命名规则,可根据需求调整URL中的文件名部分
  • 若使用fetch替代axios,需手动处理FormData的请求头,示例如下:
fetch(`https://XXX.execute-api.us-east-1.amazonaws.com/prod/XXXX/${selectedFile.name}`, {
  method: 'PUT',
  headers: {
    ...formData.getHeaders(),
    'Content-Type': selectedFile.type
  },
  body: formData
})
.then(response => response.text())
.then(result => console.log('上传成功:', result))
.catch(error => console.error('上传失败:', error));

内容的提问来源于stack exchange,提问作者lb2020

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:05:38