1

我正在使用 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);
4

1 回答 1

1

尝试使用CORS而不是package.json代理。我记得当我使用一个时遇到随机/间歇性连接问题。简而言之:前端运行在端口上3000expressAPI 运行在5000. 编译后,它们都在编译的前端 js上运行5000并提供服务,并且就像一个 API。express

非常相似的设置,但没有连接问题:

快递服务器 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

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 }))
);

express server.js(我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);
于 2018-09-25T00:45:00.823 回答