React JS连接DB API时net::ERR_CONNECTION_REFUSED错误的解决方法
React JS: DB API连接错误
我尝试连接DB API,但无法解决以下错误:
- courseApi.js:10 GET http://localhost:3001/courses/ net::ERR_CONNECTION_REFUSED
- react_devtools_backend_compact.js:2367 API调用失败。TypeError: Failed to fetch
- 未捕获的(Promise中)TypeError: Failed to fetch
at getCourses (courseApi.js:10:1)
at CoursesPage.js:9:1
App.js
import React from "react"; import HomePage from "./HomePage"; import CoursesPage from "./CoursesPage"; // import CourseForm from "./CourseForm"; import AboutPage from "./AboutPage"; import Header from "./common/Header"; import { Route, Switch, Redirect } from "react-router-dom"; import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import NotFoundPage from "./NotFoundPage"; import ManageCoursePage from "./ManageCoursePage"; function App() { return ( <div className="container-fluid"> <ToastContainer autoClose={3000} hideProgressBar /> <Header /> <Switch> <Route path="/" exact component={HomePage} /> <Route path="/courses" component={CoursesPage} /> <Route path="/course" component={ManageCoursePage} /> <Route path="/course/:slug" component={ManageCoursePage} /> <Route path="/about" component={AboutPage} /> <Route component={NotFoundPage} /> <Redirect from="/about-page" to="/about" /> </Switch> </div> ); } export default App;
index.js
import "bootstrap/dist/css/bootstrap.min.css"; import React from "react"; // import ReactDOM from "react-dom"; import { BrowserRouter as Router } from "react-router-dom"; import App from "./components/App"; import * as ReactDOM from "react-dom/client"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Router> <App /> </Router> );
CoursesPage.js
import React, { useState, useEffect } from "react"; import { getCourses } from "../api/courseApi"; import CourseList from "./CourseList"; function CoursesPage() { const [courses, setCourses] = useState([]); useEffect(() => { getCourses().then((_courses) => setCourses(_courses)); }); return ( <> <div className="container-fluid"> <h1>Course Page</h1> <a className="btn btn-primary" href="/course"> Add course </a> <CourseList courses={courses} /> </div> </> ); } export default CoursesPage;
courseApi.js
import { handleResponse, handleError } from "./apiUtils"; const baseUrl = process.env.REACT_APP_API_URL + "/courses/"; export function getCourses() { console.log(baseUrl); // console.log(handleResponse); // console.log(handleError); // debugger; console.log(window.location.href); return fetch(baseUrl).then(handleResponse).catch(handl`your text`eError); } export function getCourseBySlug(slug) { return fetch(baseUrl + "?slug=" + slug) .then((response) => { if (!response.ok) throw new Error("Network response was not ok."); return response.json().then((courses) => { if (courses.length !== 1) throw new Error("Course not found: " + slug); return courses[0]; // should only find one course for a given slug, so return it. }); }) .catch(handleError); } export function saveCourse(course) { return fetch(baseUrl + (course.id || ""), { method: course.id ? "PUT" : "POST", // POST for create, PUT to update when id already exists. headers: { "content-type": "application/json" }, body: JSON.stringify({ ...course, // Parse authorId to a number (in case it was sent as a string). authorId: parseInt(course.authorId, 10), }), }) .then(handleResponse) .catch(handleError); } export function deleteCourse(courseId) { return fetch(baseUrl + courseId, { method: "DELETE" }) .then(handleResponse) .catch(handleError); }
apiUtils.js
export async function handleResponse(response) { if (response.ok) return response.json(); if (response.status === 400) { // So, a server-side validation error occurred. // Server side validation returns a string error message, so parse as text instead of json. const error = await response.text(); throw new Error(error); } throw new Error("Network response was not ok."); } // In a real app, would likely call an error logging service. export function handleError(error) { // eslint-disable-next-line no-console console.error("API call failed. " + error); throw error; }
package.json
... "scripts": { "start": "run-p start:dev start:api", "start:dev": "cross-env REACT_APP_API_URL=http://localhost:3001 react-scripts start", "prestart:api": "node tools/createMockDb.js", ... } } ...
问题排查与修复方案
1. 核心错误原因
ERR_CONNECTION_REFUSED说明localhost:3001端口的API服务根本没启动,加上代码里的拼写错误,导致双重问题。
2. 分步修复
(1)修正courseApi.js的拼写错误
把getCourses函数里的catch(handlyour texteError)改成catch(handleError),这是明显的输入失误。
(2)完善API服务启动脚本
你的package.json里只有prestart:api(生成mock数据),但缺少start:api来启动API服务。假设用json-server做mock API:
- 先安装依赖:
npm install json-server --save-dev - 然后修改package.json的scripts:
"scripts": { "start": "run-p start:dev start:api", "start:dev": "cross-env REACT_APP_API_URL=http://localhost:3001 react-scripts start", "start:api": "json-server --port 3001 --watch tools/db.json", "prestart:api": "node tools/createMockDb.js", ... }
(3)优化useEffect执行逻辑
CoursesPage.js里的useEffect没有依赖数组,会导致组件每次渲染都重复调用API,改成:
useEffect(() => { getCourses().then((_courses) => setCourses(_courses)); }, []); // 空数组表示仅在组件挂载时执行一次
(4)验证API服务是否正常
重启项目npm start后,直接在浏览器访问http://localhost:3001/courses,如果能返回JSON数据,说明API服务正常,前端就能拿到数据了。
内容的提问来源于stack exchange,提问作者J. Nam
相关产品推荐
相关产品推荐

