React+Express POST请求卡在中间件问题求助
POST请求卡在Express中间件的排查方案
问题背景
使用React CRA构建前端、Express.js搭建后端,发起POST请求时请求卡在中间件环节。已尝试添加/移除async/await、重启服务器及本地机器,问题仍未解决。
相关代码
后端代码
server.js
var express = require('express'); var app = express(); var cors = require('cors'); const corsOptions = { origin: '*', credentials: true, optionSuccessStatus: 200, }; app.use(cors(corsOptions)); app.use("/contact", contact); app.use("/offer", offer); app.listen(3015);
index.js
var nodemailer = require('nodemailer'); var cors = require('cors'); const creds = require('../../config'); const app = express(); const corsOptions = { origin: '*', credentials: true, optionSuccessStatus: 200, }; // Multiple routing const router1 = express.Router(); const router2 = express.Router(); app.use(cors(corsOptions)); app.use(express.json()); app.use('/contact', router1); app.use('/offer', router2); app.set('port', 3015); var transport = { host: 'kelvin.superhosting.bg', port: 587, auth: { user: creds.USER, pass: creds.PASS } } var transporter = nodemailer.createTransport(transport) transporter.verify((error, success) => { if (error) { console.log(error); } else { console.log(success); // console.log('Server is ready to take messages'); } }); exports.contact = () => { router1.post('/contact', (req, res, next) => { // console.log('req.body', req.body); var name = req.body.name; var email = req.body.email; var subject = req.body.subject; var message = req.body.message; var content = `name: ${name} \n email: ${email} \n\n message: ${message} `; var mail = { from: name, to: 'sales@pokrivala.net', // Change to email address that you want to receive messages on subject: subject, text: content } transporter.sendMail(mail, (err, data) => { if (err) { console.log('err', err) res.json({ status: 'fail' }) } else { console.log('here'); res.json({ status: 'success' }) } }); next(); }); } exports.offer = async () => { await router2.post('/offer', (req, res, next) => { console.log('req.body', req.body); var subject = "Hey this is a subject example"; var mail = { to: 'sales@pokrivala.net', // Change to email address that you want to receive messages on subject: subject, attachments: [ { filename: `${req.body.attachments[0].filename}`, content: `${req.body.attachments[0].content}`, encoding: `${req.body.attachments[0].encoding}`, }, ], } transporter.sendMail(mail, (err, data) => { if (err) { res.json({ status: 'fail' }) } else { res.json({ status: 'success' }) } }); }); }
前端代码
index.jsx
async function fetchMessage() { const response = await fetch(`http://localhost:3015/contact`, { method: "POST", body: JSON.stringify(values[0]), headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, }).then( (response) => (response.json()) ).then((response) => { if (response.status === 'success') { setValues([]); setName(''); setEmail(''); setSubject(''); setMessage(''); setCaptchaText(''); onRefresh(); setMessageOpen(true); } else if (response.status === 'fail') { console.log("Message failed to send.", response) } }); return response; }
排查建议
1. 修复路由挂载逻辑
- server.js中直接挂载
contact和offer是错误的,因为这两个是导出的函数,不是Express路由实例。需要先调用函数初始化路由。 - index.js中不应重复创建Express实例
app,这会导致路由没有挂载到server.js的主app上。正确做法是仅导出路由对象,而非创建新的app。
修改示例:
// index.js 调整为只导出路由 const router1 = express.Router(); // ... 保留router1的post逻辑 exports.contactRouter = router1; // server.js 中挂载 const { contactRouter, offerRouter } = require('./path/to/index'); app.use("/contact", contactRouter);
2. 修正next()调用时机
contact路由中,next()在transporter.sendMail之前调用,而sendMail是异步操作。这会导致请求还未完成响应就交给下一个中间件,引发请求挂起。应删除next()(因为已经用res.json完成了响应),或者将next()放在sendMail的回调函数内。
3. 清理无效的async/await
offer路由中的await对router2.post毫无作用,因为router.post不返回Promise。如果要使用async/await,需将sendMail转换为Promise形式:
router2.post('/offer', async (req, res) => { try { await transporter.sendMail(mail); res.json({ status: 'success' }); } catch (err) { res.json({ status: 'fail' }); } });
4. 验证请求体解析
打开index.js中console.log('req.body', req.body)的注释,确认Express的express.json()中间件是否正确解析了前端发送的JSON数据。如果req.body为空,检查前端请求头Content-Type是否正确(已设置application/json,但需确认body是否为有效JSON)。
5. 排查Nodemailer连接问题
检查transporter.verify的输出:
- 如果打印错误,说明邮箱服务连接失败,需核对host、端口、账号密码是否正确(注意587端口是否需要TLS,可添加
secure: false, tls: { rejectUnauthorized: false }测试)。 - 如果sendMail长时间无响应,可能是邮箱服务器超时,可增加超时配置或更换测试邮箱。
6. 检查端口与跨域
确认server.js监听的是3015端口,前端请求地址http://localhost:3015/contact正确。虽然配置了CORS,但可临时简化corsOptions为app.use(cors())测试是否为跨域配置问题。
内容的提问来源于stack exchange,提问作者Santiya
相关产品推荐
相关产品推荐

