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;
关键修复点说明
- 使用选中的文件对象:直接将
event.target.files[0]添加到FormData中,替代占位符 - 动态URL文件名:根据选中文件的名称动态拼接请求URL,避免硬编码
- 对齐请求头:复用Node.js的请求头逻辑,同时设置文件的实际MIME类型和FormData自动生成的头部
- 错误处理优化:使用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
相关产品推荐
相关产品推荐

