如何同时运行Express服务器与React应用?端口冲突及最佳实践咨询
问题
之前在课堂团队项目里,能同时用npm start启动React应用、nodemon启动服务器,完全正常。现在用create-react-app搭建简单单页Web应用,发现没法让服务器和React共用3000端口,提示“端口3000已被占用”,搞不懂之前怎么实现同时运行的。
想问:二者通信是否需要共用同一端口?不管答案是是或否,对应的最佳实践是什么?
附当前项目代码:
server.js
const express = require('express') const app = express() const cors = require("cors") app.use(cors) app.use(express.json()) app.listen(3000, () => { console.log("Server is running") })
package.json
{ "name": "project", "version": "0.1.0", "private": true, "dependencies": { "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "cors": "^2.8.5", "dotenv": "^16.0.3", "express": "^4.18.2", "pg": "^8.8.0", "pg-hstore": "^2.3.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", "sequelize": "^6.27.0", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] }, "main": "./server/server.js" }
之前试过用concurrently、npm-run-all工具,但React应用和服务器都没法正常运行。旧项目和当前项目的主要区别是旧项目服务器和React各有一个package.json,而且React的package.json里有"proxy": "http://127.0.0.1:4000"配置,我在当前项目里加了这个配置也没生效,现在旧项目除了npm start外没法修复。
解答
二者通信不需要共用同一端口
同一端口同一时间只能被一个进程占用,之前团队项目能同时运行,肯定是React和服务器用了不同端口,只是通过代理配置让你看起来像是在同一端口访问接口而已。
最佳实践分两种场景:
1. 开发环境
方案A:分离端口+React代理(推荐)
- 给服务器换个端口,比如3001:修改server.js里的
app.listen(3001, ...) - 在React的package.json里添加
"proxy": "http://localhost:3001" - 启动方式:
- 终端1:
nodemon server.js启动服务器 - 终端2:
npm start启动React应用 - React里调用接口时,直接写
fetch('/api/xxx')就会被自动代理到http://localhost:3001/api/xxx
- 终端1:
方案B:用concurrently同时启动(解决你之前工具失效的问题)
- 修改package.json的scripts:
"scripts": { "start": "react-scripts start", "server": "nodemon server/server.js", "dev": "concurrently \"npm run server\" \"npm start\"" } - 确保服务器端口不是3000(比如改3001),并且React的proxy配置正确
- 运行
npm run dev就能同时启动两个服务
2. 生产环境
- 打包React应用:
npm run build - 在服务器代码里添加静态文件托管,让Express直接返回React的build文件:
const path = require('path'); app.use(express.static(path.join(__dirname, '../build'))); // 处理SPA路由,刷新页面不会404 app.get('*', (req, res) => { res.sendFile(path.join(__dirname, '../build/index.html')); }); - 只需要启动服务器(比如3000端口),就能同时提供API服务和React静态页面,实现“同一端口访问”
你当前代码的问题
- server.js里的
app.use(cors)写错了,应该是app.use(cors())(要调用函数生成中间件),这会导致CORS配置失效,可能影响接口请求 - 如果用了proxy配置,要确保服务器端口和proxy地址一致,而且React应用启动后,接口请求用相对路径才能触发代理
内容的提问来源于stack exchange,提问作者JudyBoom
相关产品推荐
相关产品推荐

