Express.js中API请求404错误排查及优化实现咨询
首先咱们先解决你遇到的404错误,再一步步优化整个实现流程:
1. 404错误的核心原因:请求路径不匹配
你提到的测试URL是http://......../books/keyword=intro,这里犯了一个基础错误:GET请求的查询参数格式是?key=value,而非/key=value。正确的请求URL应该是http://......../books?keyword=intro。
你的Express路由定义的是app.get('/books', ...),当请求/books/keyword=intro时,Express找不到对应的路由规则,自然返回404。不过看你的前端代码里的theUrl是'books?keyword=' + searchTerm,这个写法是对的,应该是你手动测试时写错了路径~
2. 后端查询逻辑的关键优化(别全表查询后再过滤!)
你当前的后端逻辑是先把books表的所有数据查出来,再用JS循环匹配关键词,这在数据量小时没问题,但数据量大时会极度低效,还浪费数据库资源。正确的做法是直接把查询条件写到SQL语句里,让数据库帮你完成过滤:
app.get('/books', function(req, res){ const { keyword } = req.query; // 注意:必须用参数化查询防止SQL注入! connection.query('SELECT * from books WHERE title LIKE ?', [`%${keyword}%`], function (error, results, fields) { if (error) { console.error(error); return res.status(500).json({ error: '数据库查询失败' }); } // 处理无匹配结果的情况 if (results.length === 0) { return res.status(404).json({ message: '未找到匹配的书籍' }); } // 返回JSON格式的结果,符合API规范 res.json(results); }); });
⚠️ 重要提醒:绝对不要直接把用户输入拼到SQL语句里,这会导致严重的SQL注入攻击!上面用的参数化查询(?作为占位符),会由数据库连接库自动处理转义,保证查询安全。
3. 前端代码的修复与体验优化
你的前端代码有几个小问题需要调整,同时可以提升用户体验:
- 重复的
id="search":输入框和结果div用了同一个id,会导致DOM选择出错,把结果div的id改成search-result; - XHR的语法错误:
if (xhttp.readyState == XMLHttpRequest.DONE);多了个分号,会导致后续代码无论请求状态如何都会执行,还要增加status === 200的判断确保请求成功; - 增加错误处理:比如网络错误、服务器返回异常状态码的情况;
- 增加回车触发搜索的功能,提升用户体验。
优化后的前端代码:
<!DOCTYPE html> <html> <head> <title>书籍搜索</title> </head> <body> <div id="data"> <input type="button" id="button" value="搜索书籍"/> <input type="text" id="search-input" placeholder="输入书名关键词"> </div> <div id="search-result"></div> <script> document.getElementById('button').addEventListener('click', getUserInput); // 增加回车触发搜索 document.getElementById('search-input').addEventListener('keypress', function(e) { if (e.key === 'Enter') getUserInput(); }); function getUserInput(event){ const userInput = document.getElementById("search-input").value.trim(); if(userInput !== ""){ httpGetAsync(userInput); } else { alert('请输入搜索关键词'); } } function httpGetAsync(searchTerm){ // 对搜索关键词编码,处理特殊字符 const theUrl = 'books?keyword=' + encodeURIComponent(searchTerm); const xhttp = new XMLHttpRequest(); xhttp.open("GET", theUrl, true); xhttp.send(); xhttp.onreadystatechange = function() { if (xhttp.readyState === XMLHttpRequest.DONE) { if (xhttp.status === 200) { try { const results = JSON.parse(xhttp.response); displayResults(results); } catch (e) { console.error('解析响应失败', e); document.getElementById('search-result').textContent = '数据解析错误'; } } else if (xhttp.status === 404) { document.getElementById('search-result').textContent = '未找到匹配的书籍'; } else { document.getElementById('search-result').textContent = `请求失败,状态码:${xhttp.status}`; } } }; } // 渲染搜索结果到页面 function displayResults(results) { const resultDiv = document.getElementById('search-result'); resultDiv.innerHTML = ''; if (results.length === 0) { resultDiv.textContent = '未找到匹配的书籍'; return; } const ul = document.createElement('ul'); results.forEach(book => { const li = document.createElement('li'); // 根据你的数据库表结构调整显示字段 li.textContent = `${book.title} - ${book.author || '未知作者'}`; ul.appendChild(li); }); resultDiv.appendChild(ul); } </script> </body> </html>
4. 关于keyword=intro格式的疑问
keyword=intro是GET请求查询参数的标准格式,完全没问题!Express会自动把URL中的查询参数解析到req.query对象里,所以你用const { keyword } = req.query;的写法是完全正确的。
按照上面的方案调整后,应该就能解决404问题,同时让整个搜索功能更高效、安全、易用啦!
内容的提问来源于stack exchange,提问作者Christopher Bovo

