AWS部署的React+Express应用文件上传POST请求无响应求助
我在AWS部署了一套React+Express生产环境应用,整体运行基本正常,但向Express服务器发起文件上传POST请求时无任何响应,本地环境下该功能可正常上传文件并推送至API。同时Nginx出现错误:Upstream prematurely closed connection while reading response header from upstream。以下是相关代码配置,恳请提供解决建议:
server.js
const express = require('express'); const path = require('path'); const docparser = require('docparser-node'); const client = new docparser.Client("APIKEY"); const parserID = "cslfmvewjrvo"; const multer = require('multer'); const app = express(); //this creates the filestream needed to upload to API endpoint const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, 'client/public/uploads') }, filename: function (req, file, cb) { cb(null, file.originalname) } }) const upload = multer({ storage }); const fs = require('fs') // Upload Route app.post('/api/upload', upload.single('file'), async (req, res) => { const file = req.file; const stream = fs.createReadStream(`${__dirname}/../client/public/uploads/${file.filename}`); if (file == null) { return res.status(400).json({ msg: 'No file uploaded' }); } try { let result = await client.uploadFileByStream(parserID, stream); let docID = result.id; console.log("This is the document ID: " + docID); console.log("waiting for response..."); //We have to wait for a response from the API so thats what delay is for await delay(20000); let parsedData = await client.getResultsByDocument(parserID,docID, {format: 'object'}); let transcript = parsedData[0].final; return res.status(200).send(transcript); } catch (err) { console.error(err) return res.status(500).json({ msg: 'An error occurred' }) } }); // This function delays the actions of whatever code precedes it function delay(time) { return new Promise(resolve => setTimeout(resolve, time)); }; app.listen(5000, () => console.log('Server Started...'));
FileUpload.js
//FileUpload.js import React, { Fragment, useState, useEffect,useMemo } from 'react'; import axios from 'axios'; import Table from "./Table"; import Message from './Message'; import Progress from './Progress'; import '../App.css'; //This is the fileUploader Component. const FileUpload = () => { const [file,setFile] = useState(''); const [fileName,setFileName] = useState('Choose File'); const [data,setData] = useState([]); const [uploadedFile, setUploadedFile] = useState({}); const [message, setMessage] = useState(''); const [uploadPercentage, setUploadPercentage] = useState(0); const [tableData,setTableData] = useState(true); const onChange = e => { setFile(e.target.files[0]); setFileName(e.target.files[0].name); }; const onSubmit = async e => { e.preventDefault(); const formData = new FormData(); formData.append('file', file); try { const res = await axios.post('/api/upload', formData, { headers: { 'Content-Type': 'multipart/form-data' }, onUploadProgress: progressEvent => { setUploadPercentage( parseInt( Math.round((progressEvent.loaded * 100) / progressEvent.total) ) ); } }); setData(res.data); console.log(setData); setTableData(false); // Clear percentage setTimeout(() => setUploadPercentage(0), 10000); const { fileName, filePath } = res.data; setUploadedFile({ fileName, filePath }); setMessage('Transcript Uploaded'); } catch (err) { if (err.response.status === 500) { setMessage('There was a problem with the server'); } else { setMessage(err.response.data.msg); } setUploadPercentage(0) } }; /* - Columns is a simple array right now, but it will contain some logic later on. It is recommended by react-table to memoize the columns data - Here in this example, we have grouped our columns into two headers. react-table is flexible enough to create grouped table headers */ const columns = useMemo( () => [ { // first group - Schedule Header: "Schedule", // First group columns columns: [ { Header: "Course", accessor: "course" }, { Header: "Coursename", accessor: "coursename" }, { Header: "Attempted", accessor: "attempted" }, { Header: "Received", accessor: "received" } , { Header: "Grade", accessor: "grade" } ] } ], [] ); return ( <Fragment> {message ? <Message msg={message} /> : null} <form onSubmit={onSubmit}> <div className='custom-file mb-4'> <input type='file' className='custom-file-input' id='customFile' onChange={onChange} /> <label className='custom-file-label' htmlFor='customFile'> {fileName} </label> </div> <Progress percentage={uploadPercentage} /> <input type='submit' value='Upload' className='btn btn-primary btn-block mt-4' /> </form> {uploadedFile ? ( <div className='row mt-5'> <div className='col-md-6 m-auto'> <h3 className='text-center'>{uploadedFile.fileName}</h3> <img style={{ width: '100%' }} src={uploadedFile.filePath} alt='' /> </div> </div> ) : null} {tableData ? ( <p/> ): ( <Table columns={columns} data={data} /> ) } </Fragment> ); }; export default FileUpload
Nginx 配置
server { server_name 52.200.122.98; # react app & front-end files location / { root /home/ubuntu/KUAutoadvisor/client/build/; try_files $uri /index.html; } # node api reverse proxy // the /api/ is assuming your api routes start with that i.e. www.your-site.com/api/endpoint location /api/ { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-NginX-Proxy true; proxy_http_version 1.1; proxy_pass http://localhost:5000; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; proxy_read_timeout 300s; proxy_connect_timeout 75s; proxy_max_temp_file_size 4096m; } }
检查Multer存储目录权限
AWS服务器上client/public/uploads目录可能不存在或权限不足,导致Express无法写入文件。执行以下命令创建目录并设置权限:mkdir -p /home/ubuntu/KUAutoadvisor/client/public/uploads chmod -R 755 /home/ubuntu/KUAutoadvisor/client/public/uploads chown -R ubuntu:ubuntu /home/ubuntu/KUAutoadvisor/client/public/uploads修正Multer路径问题
相对路径在生产环境可能不可靠,改用绝对路径并确保目录存在:const uploadDir = path.resolve(__dirname, '../client/public/uploads'); // 自动创建目录(如果不存在) if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } const storage = multer.diskStorage({ destination: function (req, file, cb) { cb(null, uploadDir) }, filename: function (req, file, cb) { cb(null, file.originalname) } })调整超时设置
你的代码中有20秒延迟,加上文件上传和API请求时间,可能触发超时。在Express中显式设置更长超时:app.set('timeout', 300000); // 设置为5分钟Nginx的
proxy_read_timeout 300s已经足够,但确保没有其他隐性超时限制。排查Express错误日志
增强错误处理,输出详细错误信息,便于定位问题:catch (err) { console.error('上传失败详情:', err); return res.status(500).json({ msg: 'An error occurred', error: err.message }) }同时查看Express的控制台输出,确认是否有文件读取失败、docparser API调用错误等问题。
直接测试Express接口
跳过Nginx,在服务器上用curl直接测试上传接口,判断问题出在Express还是Nginx:curl -X POST -F "file=@/path/to/test/file" http://localhost:5000/api/upload如果请求正常,说明问题在Nginx配置;如果失败,说明Express端存在问题。
检查Nginx请求转发
在Nginx的/api/location块中添加proxy_set_header X-Real-IP $remote_addr;,便于调试请求来源。同时确认Nginx有权限转发到localhost:5000,没有防火墙或安全组限制。
内容的提问来源于stack exchange,提问作者C H

