Express通过Axios向React返回数据失败:Promise pending问题排查
问题
我正在开发一款追踪厨师及其发布新食谱的应用:前端基于React实现,可输入厨师用户名并发送至Express后端;后端通过cheerio爬取美食网站的对应食谱数据,但无法将数据返回给前端。
测试时使用用户名"John",前端收到空对象,后端控制台显示Promise { <pending> }或仅能在终端看到响应。请问我哪里出错了,为什么会出现Promise pending状态?
前端代码
export const FindUsername = () => { const usernameRef = useRef(null) const [ username, setUsername ] = useState(''); const handleClick = async () => { setUsername(usernameRef.current.value); const response = await axios.get(`http://localhost:3001/user/${username}`) .then(res => { //console.log(res); console.log(res) }) console.log(response) } return ( <Stack direction="row"> <TextField id="outlined-basic" label="Username" variant="outlined" inputRef={usernameRef}/> <Button variant="contained" onClick={handleClick}>Find User {username}</Button> </Stack> ); }
后端爬取模块代码
const axios = require('axios'); const cheerio = require('cheerio'); const fs = require('fs'); const searchWithUsername = async (username) => { const targetURL = "https://www.xxxxxxx.com/profile/" + username + "/recipes"; const {data} = await axios.get(targetURL); const recipes = []; const $ = cheerio.load(data); $('.css-1xwc2tk').each((index, element) => { const recipe = $(element).find('.recipe_title').text() recipes.push(recipe) }) return recipes; } module.exports = searchWithUsername;
后端路由代码
router.get('/', function(req, res, next) { const username = req.user_config.user; console.log('Got body:', req.user_config.user); console.log(searchWithUsername(username)); res.type('application/json') //res.send("OK") res.send(searchWithUsername(username).then()); //res.sendStatus(200); });
问题分析与修复方案
核心问题:异步代码未正确处理+路由参数匹配错误
searchWithUsername是异步函数,调用后返回Promise。你直接打印Promise或通过searchWithUsername(username).then()传值给res.send,没有等待异步操作完成就返回响应,导致前端收到空数据,后端显示Promise { <pending> }。- 前端通过URL路径传递用户名,但后端错误地从
req.user_config.user获取参数,无法拿到正确的用户名,爬取路径无效。
修复步骤
1. 修复后端路由的异步处理与参数获取
将路由处理函数改为异步函数,用await等待爬取完成,同时从URL参数中正确获取用户名:
// 匹配前端请求的/user/:username路径 router.get('/user/:username', async function(req, res, next) { const username = req.params.username; // 从URL参数中读取用户名 console.log('Got username:', username); try { // 等待异步爬取完成 const recipes = await searchWithUsername(username); console.log(recipes); // 打印实际爬取的食谱数组 res.type('application/json'); res.send(recipes); // 返回有效数据给前端 } catch (error) { console.error('爬取或请求失败:', error); res.status(500).send({ error: '无法获取食谱数据' }); // 错误处理 } });
2. 优化前端代码(冗余写法修正+避免旧值问题)
前端同时混用await和.then()写法冗余,且setUsername是异步操作,直接用username拼接URL可能拿到旧值,建议修正:
export const FindUsername = () => { const usernameRef = useRef(null) const [ username, setUsername ] = useState(''); const handleClick = async () => { const inputUsername = usernameRef.current.value; setUsername(inputUsername); try { // 直接使用inputUsername避免异步更新延迟问题 const response = await axios.get(`http://localhost:3001/user/${inputUsername}`); console.log('后端返回数据:', response.data); // 这里可以添加数据处理逻辑,比如存储到state } catch (error) { console.error('请求失败:', error); } } return ( <Stack direction="row"> <TextField id="outlined-basic" label="Username" variant="outlined" inputRef={usernameRef}/> <Button variant="contained" onClick={handleClick}>Find User {username}</Button> </Stack> ); }
内容的提问来源于stack exchange,提问作者JBravo
相关产品推荐
相关产品推荐

