React应用中Axios报Invalid HTTP Response错误,求排查解决
问题:React本地应用通过Axios调用本地API获取MySQL数据时返回Invalid HTTP Response错误
我在本地运行的React应用中,使用Axios从本地MySQL数据库获取数据,调用Axios时控制台返回Invalid HTTP Response错误。我的MySQL数据库运行在3306端口,所以把API服务器也部署在了这个端口。
相关代码
API接口代码
import axios from 'axios'; const AxiosConfigured = () => { axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; axios.defaults.baseURL = 'http://localhost:3306/api'; axios.defaults.withCredentials = true; return axios; } const axiosAgent = AxiosConfigured(); export default class APIInterface { async getCategories(id) { console.log("getCalegories in API_Interface called."); return axiosAgent.get('/cats/${id}') .then(catInfo => catInfo.data) .catch(error => ( { error, cat: undefined })); } }
API服务器代码
import db from './database.js' import express from 'express'; import cors from 'kcors'; import bodyParser from 'body-parser'; import httpServer from './ssl.js'; import routes from './routes.js'; const app = express(); const corsOpstions = { origin: ['http://localhost:3306/api'], credentials: true, exposeHeaders: ['Access-Token', 'Cookie'], methods: ["GET"] }; app.use(cors(corsOpstions)); app.use(bodyParser.json()); app.use(async (ctx, next) =>{ await next(); if (ctx.response.status === 204) { ctx.response.contentlength = 0; } console.log('in api_server.js: ctx.status is ${ctx.status}.'); return next().catch((err) => { if(err.status === 401) { console.log('index.js: sending 401 to client.'); ctx.status = 401; ctx.body = 'Something went wrong...'; } else { console.log('index.js: exception fired'); console.log('The error message is ${err}.'); } }); }); routes(app); app.listen(3306, () => { console.log('Server started on port 3306'); });
路由代码
import koarouter from 'koa-router'; import catController from './catController.js'; /************* DEFAULT ROUTER ***************/ const router = new koarouter({ prefix: '/api' }) router.get('/', function (ctx) { console.log('router.get(/)'); return ctx.body = 'Default router'; }) /********************************************/ const CatController = new catController(); const catRouter = new koarouter({ prefix: '/cats' }); catRouter.get('/:id', CatController.getCats, (err) => console.log("router.js: catRouter error: ", err)); router.use( '', catRouter.routes() ); export default function (app) { app.use(router.routes()); app.use(router.allowedMethods()); }
控制器代码
import db from './database.js'; class CatController { async getCats(ctx) { console.log('getCats called.'); return new Promise((resolve, reject) => { let query = " SELECT * FROM Categories WHERE id = ?"; db.query( { sql: query, values: ctx.params.id }, (error, tuples) => { if (error) { console.log("Query error.", error) return reject('Query error. Error msg: ${error}.'); } if (tuples.length === 1) { console.log("Category id matched: ", tuples[0]); ctx.body = { cat: tuples[0] }; } else { console.log('Not able to identify category...'); return reject("No such category."); } return resolve(); } ) }).catch(err => { console.log("getCats in CatController threw an exception. Reason: ", err); ctx.body = { status: "Failed", error: err, cat: null }; }); } } export default CatController;
数据库连接代码
import mysql from 'mysql2'; const db = mysql.createConnection({ host: 'localhost', port: 3306, user: 'root', password: 'password', database: 'Jeoprady_QandAs' }); db.connect((err) => { if(err) { console.error('Error connecting to MySQL: ' + err.stack); return; } console.log('Connected to MySQL as ID ' + db.threadId); }); export default db;
API调用代码
const [cat, setCat] = useState([]); useEffect(() => { const api = new API; async function getCat() { console.log('CatRows.js: getCat useEffect called.'); api.getCategories(0) .then(catInfo => { console.log('API returns category info and it is :${JSON.stringify(catInfo)}'); const cat = catInfo.cat; setCat(cat); }); } getCat(); }, []); console.log('In CatRows.js the category returned is: ${cat}.');
我尝试调整Axios请求头与CORS配置,但无效果;也尝试将API服务器切换至其他端口,问题依旧。期望API调用能返回与给定ID匹配的数据库分类数据。
问题分析与修复方案
1. 核心问题:Express与Koa框架混用
你的API服务器用express()创建了应用实例,但中间件使用了Koa的ctx上下文语法,路由用了koa-router——这两个框架完全不兼容,导致服务器无法正确处理HTTP请求,直接返回无效响应,这是Invalid HTTP Response的根本原因。
2. 其他关键错误
- 端口冲突:MySQL已经占用3306端口,API服务器必须换用其他端口(比如3001),否则无法启动。
- 模板字符串语法错误:API接口中
axiosAgent.get('/cats/${id}')使用单引号,模板变量不会被解析,应该改用反引号:axiosAgent.get(`/cats/${id}`)。 - CORS配置错误:
origin应该设置为React应用的地址(比如http://localhost:3000),而非API自身地址,否则浏览器会拦截跨域请求。 - API实例化错误:调用时
new API应该改为new APIInterface,因为导出的类是APIInterface。 - 控制器Promise处理问题:查询成功后设置
ctx.body即可,无需额外返回Promise;错误处理应直接设置响应状态码和body,避免Promise嵌套导致的响应异常。
修复后的代码示例
改用Koa作为API服务器(推荐,因为路由用了koa-router)
// api_server.js import db from './database.js' import Koa from 'koa'; import cors from '@koa/cors'; import bodyParser from 'koa-bodyparser'; import routes from './routes.js'; const app = new Koa(); const corsOptions = { origin: 'http://localhost:3000', // React应用地址 credentials: true, exposeHeaders: ['Access-Token', 'Cookie'], methods: ["GET"] }; app.use(cors(corsOptions)); app.use(bodyParser()); app.use(async (ctx, next) =>{ try { await next(); if (ctx.response.status === 204) { ctx.response.length = 0; } console.log(`in api_server.js: ctx.status is ${ctx.status}.`); } catch (err) { if(err.status === 401) { console.log('index.js: sending 401 to client.'); ctx.status = 401; ctx.body = 'Something went wrong...'; } else { console.log('index.js: exception fired'); console.log(`The error message is ${err}.`); ctx.status = 500; ctx.body = { status: 'Failed', error: err.message }; } } }); routes(app); app.listen(3001, () => { // 换用3001端口,避免和MySQL冲突 console.log('Server started on port 3001'); });
修复后的API接口代码
// APIInterface.js import axios from 'axios'; const AxiosConfigured = () => { axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; axios.defaults.baseURL = 'http://localhost:3001/api'; // 对应API服务器新端口 axios.defaults.withCredentials = true; return axios; } const axiosAgent = AxiosConfigured(); export default class APIInterface { async getCategories(id) { console.log("getCategories in API_Interface called."); try { const catInfo = await axiosAgent.get(`/cats/${id}`); // 改用反引号 return catInfo.data; } catch (error) { console.error('Axios request error:', error); return { error, cat: undefined }; } } }
修复后的API调用代码
// CatRows.js const [cat, setCat] = useState(null); // 初始值设为null更合理 useEffect(() => { const api = new APIInterface; // 修正类名 async function getCat() { console.log('CatRows.js: getCat useEffect called.'); const catInfo = await api.getCategories(0); // 改用async/await更清晰 console.log(`API returns category info: ${JSON.stringify(catInfo)}`); // 反引号 setCat(catInfo.cat); } getCat(); }, []); console.log(`In CatRows.js the category returned is: ${JSON.stringify(cat)}.`); // 反引号+JSON.stringify
验证步骤
- 确保MySQL服务在3306端口正常运行。
- 启动修复后的API服务器(端口3001)。
- 启动React应用(默认3000端口),检查控制台是否还有错误,查看是否成功获取分类数据。
内容的提问来源于stack exchange,提问作者Ethan Zogg
相关产品推荐
相关产品推荐

