React客户端按ID获取事件数据页面空白问题排查
问题描述
我想从SQL表中获取指定事件的数据,期望在客户端URL(http://localhost:3000/dashboard/)后添加对应的keyInfo_id时,页面只展示该ID的事件数据,而非全部事件。但目前访问http://localhost:3000/dashboard/3(3是MySQL生成的事件ID)时,页面空白无内容,不清楚原因。
服务端代码
/* GET event listing by ID */ router.get('/:keyInfo_id', async function (req, res, next) { let { keyInfo_id } = req.params; try { let result = await db(`SELECT activities.keyInfo_id, date, title, deadline, activities_id, activityName, description, price, location FROM activities INNER JOIN keyInfo ON keyInfo.keyInfo_id = activities.keyInfo_id WHERE keyInfo.keyInfo_id = ${keyInfo_id} `); let event = result.data; if (event.length !== 0) { res.send(event); } else { // event array is empty... no event found res.status(404).send({ error: 'Event not found' }); } }catch (err) { res.status(500).send({error: err.message}); } });
客户端React代码
function App() { let [allEvents, setAllEvents] = useState([]); // useEffect() will call getEvent() when App is mounted on the DOM useEffect(() => { getEvent(); }, []); // the empty [] means only call it once //Get all the events async function getEvent() { try { let response = await fetch('/event'); if (response.ok) { let data = await response.json(); setAllEvents(data); } else { console.log(`Server error: ${response.status}: ${response.statusText}`); } } catch(err) { console.log(`Network error: ${err.message}`); } } // Get all the events by ID async function getEvent(id) { try { let response = await fetch('/:keyInfo_id'); if (response.ok || response === id ) { let data = await response.json(); setAllEvents(data); } else { console.log(`Server error: ${response.status}: ${response.statusText}`); } } catch(err) { console.log(`Network error: ${err.message}`); } } }
问题分析与修复方案
核心问题点
- 路由未读取URL参数:React组件没有从
/dashboard/:keyInfo_id路径中提取ID参数,也没有根据参数触发单个事件的请求。 - 接口请求地址错误:获取单个事件的
getEvent(id)函数中,请求URL写死为/:keyInfo_id,这不是有效接口地址,需替换为带实际ID的路径。 - 函数重名冲突:两个
getEvent函数同名,导致后定义的函数覆盖前一个,初始化调用的无参getEvent实际无效。 - SQL注入风险:直接将
keyInfo_id拼接进SQL语句,存在安全漏洞。
修复步骤
1. 处理React路由,读取URL参数
使用react-router-dom获取URL中的ID参数,并根据参数决定请求全部事件还是单个事件:
import { useParams } from 'react-router-dom'; function App() { let [allEvents, setAllEvents] = useState([]); const { keyInfo_id } = useParams(); // 提取URL中的ID参数 useEffect(() => { if (keyInfo_id) { getEventById(keyInfo_id); // 有ID则请求单个事件 } else { getAllEvents(); // 无ID则请求全部事件 } }, [keyInfo_id]); // ID变化时重新请求 // 重命名函数避免冲突,获取全部事件 async function getAllEvents() { try { let response = await fetch('/event'); if (response.ok) { let data = await response.json(); setAllEvents(data); } else { console.log(`Server error: ${response.status}: ${response.statusText}`); } } catch(err) { console.log(`Network error: ${err.message}`); } } // 修复请求地址,获取单个事件 async function getEventById(id) { try { let response = await fetch(`/event/${id}`); // 替换为实际接口地址 if (response.ok) { let data = await response.json(); setAllEvents(data); } else if (response.status === 404) { console.log('事件不存在'); setAllEvents([]); } else { console.log(`Server error: ${response.status}: ${response.statusText}`); } } catch(err) { console.log(`Network error: ${err.message}`); } } // 渲染事件数据 return ( <div> {allEvents.length === 0 ? ( <p>暂无事件数据</p> ) : ( allEvents.map(event => ( <div key={event.keyInfo_id}> <h3>{event.title}</h3> <p>{event.description}</p> {/* 渲染其他事件字段 */} </div> )) )} </div> ); }
2. 修复服务端SQL注入问题
改用参数化查询,避免直接拼接SQL:
router.get('/:keyInfo_id', async function (req, res, next) { let { keyInfo_id } = req.params; try { // 参数化查询,语法根据使用的数据库库调整(示例为mysql2) let [result] = await db.query( `SELECT activities.keyInfo_id, date, title, deadline, activities_id, activityName, description, price, location FROM activities INNER JOIN keyInfo ON keyInfo.keyInfo_id = activities.keyInfo_id WHERE keyInfo.keyInfo_id = ?`, [keyInfo_id] ); let event = result; if (event.length !== 0) { res.send(event); } else { res.status(404).send({ error: 'Event not found' }); } }catch (err) { res.status(500).send({error: err.message}); } });
3. 确认接口路由前缀
确保服务端路由挂载前缀为/event,比如:
// app.js中挂载路由 const eventRouter = require('./routes/event'); app.use('/event', eventRouter);
这样服务端/:keyInfo_id路由对应的完整接口地址为/event/3,与客户端请求地址匹配。
内容的提问来源于stack exchange,提问作者Kelly Tran
相关产品推荐
相关产品推荐

