我正在使用create-react- app(因此没有自定义webpack)和节点服务器构建MERN应用程序。我正在使用nodemon重新启动后端的更改,问题是大约有一半的时间,我的前端似乎在nodemon可以重新启动节点服务器之前尝试呈现,从而导致ECONNREFUSED错误。
我可以通过刷新页面来解决此问题,但是必须重复执行此操作很烦人,我只想弄清楚问题可能是什么。如果我运行节点服务器而不是nodemon,则不会发生这种情况。
这是我的客户端package.json的相关部分:
"scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" }, "proxy": "http://localhost:7777"
和服务器端package.json:
"scripts": { "client-install": "npm intall --prefix client", "start": "node server.js", "server": "nodemon server.js", "client": "cd client && npm start", "dev": "concurrently \"npm run server\" \"npm run client\"" }
和我的server.js
const express = require('express'); const bodyParser = require('body-parser'); const mongoose = require('mongoose'); const path = require('path'); const routes = require('./routes/index'); require('dotenv').config(); const app = express(); app.use(bodyParser.json()); mongoose.connect(process.env.DATABASE, {useNewUrlParser: true}) .then(() => console.log('MongoDb connected')) .catch(err => console.log(`Mongo error ${err}`)) const port = process.env.PORT || 7777; app.use('/', routes); if (process.env.NODE_ENV === 'production') { // Serve any static files app.use(express.static(path.join(__dirname, 'client/build'))); // Handle React routing, return all requests to React app app.get('*', function(req, res) { res.sendFile(path.join(__dirname, 'client/build', 'index.html')); }); } app.listen(port, () => { console.log(`Connected at port ${port}`) })
我将axios用于前端HTTP请求:
import axios from 'axios'; import FormData from 'form-data' import keys from '../keys'; export const getPosts = () => { return axios.get('/api') } export const post = (file, bodyInfo) => { let formData = new FormData(); formData.append('file', file[0], file[0].name); formData.append('bodyInfo', JSON.stringify(bodyInfo)); return axios.post('/api', formData, { headers: { 'Content-Type': `multipart/form-data; boundary=${formData._boundary}`, } }) } export const getSinglePhoto = (id) => { return axios.get(`/api/${id}`); } export const postUser = (userDetails) => { console.log(userDetails); return axios.post('/api/user', userDetails) } export const getUser = () => { return axios.get('/user'); } export const removeUser = (id) => { return axios.delete(`/user/${id}`) }
这是我的路线:
router.get('/api', postController.getPosts); router.post('/api', postController.type, postController.uppic, postController.cloudinary ); router.get('/api/:id', postController.getSingle); router.get('/user', userController.getUser); router.post('/api/user', userController.postUser); router.delete('/user/:id', userController.removeUser);
尝试使用CORS代替package.json代理。我记得当我使用一个随机/间歇性连接问题时。简而言之:前端在port 上运行3000,expressAPI在上运行5000。编译后,它们都可以在已编译的前端js 上运行5000并express提供服务,并且类似于API。
CORS
package.json
3000
express
5000
设置非常相似,但没有连接问题:
快递服务器package.json
... "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "NODE_ENV=production node app.js", "server": "NODE_ENV=development nodemon app.js", "client": "npm run start --prefix client", "dev": "concurrently \"npm run server\" \"npm run client\"", "seeds": "NODE_ENV=development node seeds.js" }, ...
client / package.json (使用Sass编译器,您可以使用/忽略)。
... "scripts": { "build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules src/ -o src/", "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive", "start-js": "react-scripts start", "start": "npm-run-all -p watch-css start-js", "build": "npm run build-css && react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" }, ...
client / src / actions / axiosConfig.js (然后,我创建一个axios配置以自动指向在上运行的Express API 5000)
axios
import axios from 'axios'; export const app = axios.create({ baseURL: 'http://localhost:5000/api/', withCredentials: true })
client / src / actions / authActions.js (然后导入axios配置)
import { app } from './axiosConfig'; const signinUser = props => dispatch => ( app.post(`signin`, { ...props }) .then(({data}) => { dispatch({ type: types.SET_SIGNEDIN_USER, payload: data }) dispatch(fetchAvatarOnLogin()); }) .catch(err => dispatch({ type: types.SERVER_ERROR, payload: err })) );
表达server.js (我consign用来导入所有文件):
consign
const express = require('express'); const app = express(); const consign = require('consign'); consign({ locale: 'en-us', verbose: false}) .include('libs/middlewares.js') .then("database") .then("shared") .then("services") .then("controllers") .then("routes") .then('libs/server.js') .into(app);
但是,等效项为:
// APP REQUIRED IMPORTS const express = require('express'); const app = express(); ...etc // APP MIDDLEWARES ... app.use(cors({credentials: true, origin: http://localhost:3000})) // allows receiving of cookies from front-end app.use(morgan('tiny')); // logging framework app.use(bodyParser.json()); // parses header requests (req.body) app.use(bodyParser.urlencoded({ extended: true })); // allows objects and arrays to be URL-encoded ...etc // DATABASE CONFIG/CONN // APP SHARED FUNCS // APP SERVICES (passport, sendgrid mailer, ...etc) // APP CONTROLLERS ... signin: (req, res, done) => passport.authenticate('local-login', err => ( (err || !req.session) ? sendError(err || badCredentials, res, done) : res.status(201).json({ ...req.session })) )(req, res, done) ...etc // APP ROUTES ... app.post('/api/signin', signin); ...etc // EXPRESS SERVER if (process.env.NODE_ENV === 'production') { app.use(express.static('client/build')); app.get('*', (req, res) => res.sendFile(path.resolve('client', 'build', 'index.html'))); } app.listen(5000);