React Express Routing在本地工作,但不适用于Heroku

时间:2018-11-04 01:56:05

标签: node.js express heroku

我开发了一个使用路由器文件 feedback.router.js 的应用。我已将服务器设置为导入此路由器文件,并将其用于'/feedback'请求。

我使用各种GET,POST,DELETE,PUT路由与数据库进行通信。在本地,我的应用程序axios请求已正确路由,并与我的数据库正确集成。在我的server.js文件中,我阅读了其他问题,并实现了我认为express应该用于生产版本的内容。当我在Heroku上运行该应用程序时,我从任何axios请求中收到的响应似乎都是HTML文件,该文件指示无法识别该路由,但是我无法确定该错误。我相信我为Heroku正确设置了数据库,尽管问题可能出在这里。

一个突出的间接问题是我不知道一旦部署在Heroku上后如何解决这些类型的请求。我已经将它与我在Github上的存储库连接了,但是找不到任何“服务器终端”来协助错误查找。非常欢迎提供任何有关如何使用Heroku解决此问题的建议。

更新以包含GET和POST请求的Heroku日志:

  

2018-11-04T03:20:11.564616 + 00:00 heroku [router]:at = info method = POST   path =“ / feedback” host = prime-feedback-app.herokuapp.com   request_id = 65732134-d050-4f82-ab08-9d0764266cb3 fwd =“ 73.242.14.56”   dyno = web.1 connect = 0ms服务= 3ms status = 200字节= 2377   protocol = https

     

2018-11-04T03:21:05.866976 + 00:00 heroku [router]:   at = info method = GET path =“ / feedback”   host = prime-feedback-app.herokuapp.com   request_id = 6b1b7341-5dbf-443d-bff4-e0a6e3080e51 fwd =“ 73.242.14.56”   dyno = web.1 connect = 0ms服务= 3ms status = 200字节= 2377   协议= https

我提供了我认为可能有用的文件。

文件结构(星号表示文件夹)

feedback-app
    **build**
    **public**
    **server**
        **modules**
             pool.js
        **routes**
             feedback.router.js
        server.js
    **src**
        **components**
             ...
        index.js
        registerServiceWorker.js
     data.sql
     package.json
     package-lock.json

我的axios请求示例:

axios({
    method: 'GET',
    url: '/feedback'
}).then((response) => {
    console.log('response:',response);
    this.setState({
        display: 'all',
        feedback: response.data
    });
}).catch((error) => {
    console.log('error',error);
})

server.js

    const express = require('express');
    const app = express();
    const bodyParser = require('body-parser');
    const path = require('path');
    const PORT = process.env.PORT || 5000;
    const feedbackRouter = require('./routes/feedback.router');

    /** ---------- MIDDLEWARE ---------- **/
    app.use(bodyParser.json()); // needed for angular requests
    app.use(bodyParser.urlencoded({extended: true}));

    if (process.env.NODE_ENV === 'production') {
        // Exprees will serve up production assets
        app.use(express.static(path.join(__dirname, 'build')));

        // Express serve up index.html file if it doesn't recognize route
        app.get('*', (req, res) => {
          res.sendFile(path.join(__dirname, 'build', 'index.html'));
        });
    }

    /** ---------- EXPRESS ROUTES ---------- **/
    app.use('/feedback', feedbackRouter);

    /** ---------- START SERVER ---------- **/
    app.listen(PORT, () => {
        console.log('Listening on port: ', PORT);
    });

pool.js

const pg = require('pg');
const url = require('url');
let config = {};

if (process.env.DATABASE_URL) {
    // Heroku gives a url, not a connection object
    // https://github.com/brianc/node-pg-pool
    let params = url.parse(process.env.DATABASE_URL);
    let auth = params.auth.split(':');

    config = {
        user: auth[0],
        password: auth[1],
        host: params.hostname,
        port: params.port,
        database: params.pathname.split('/')[1],
        ssl: true, // heroku requires ssl to be true
        max: 10, // max number of clients in the pool
        idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
    };

} else {
    // only change the things on the right side of the ||
    config = {
        user: process.env.PG_USER || null, //env var: PGUSER
        password: process.env.DATABASE_SECRET || null, //env var: PGPASSWORD
        host: process.env.DATABASE_SERVER || 'localhost', // Server hosting the postgres database
        port: process.env.DATABASE_PORT || 5432, //env var: PGPORT
        database: process.env.DATABASE_NAME || 'prime_feedback', //env var: PGDATABASE or the name of your database (e.g. database: process.env.DATABASE_NAME || 'koala_holla',)
        max: 10, // max number of clients in the pool
        idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
    };
}

module.exports = new pg.Pool(config);

package.json

{
  "name": "react-reflection-board",
  "version": "0.1.0",
  "private": true,
  "proxy": "http://localhost:5000",
  "engines": {
    "npm": "6.4.1",
    "node": "10.11.0"
  },
  "dependencies": {
    "@material-ui/core": "^3.3.2",
    "@material-ui/icons": "^3.0.1",
    "axios": "^0.17.1",
    "bootstrap": "^4.1.3",
    "pg": "^7.4.1",
    "react": "^16.3.0",
    "react-confirm-alert": "^2.0.6",
    "react-dom": "^16.3.0",
    "react-progressbar": "^15.4.1",
    "react-redux": "^5.1.0",
    "react-router-dom": "^4.3.1",
    "react-scripts": "^2.1.1",
    "react-swal": "^3.0.0",
    "reactstrap": "^6.5.0",
    "recompose": "^0.30.0",
    "redux": "^4.0.1",
    "redux-logger": "^3.0.6",
    "serve": "^10.0.2"
  },
  "devDependencies": {
    "nodemon": "^1.18.5"
  },
  "scripts": {
    "dev": "react-scripts start",
    "start": "serve -s build",
    "build": "react-scripts build",
    "heroku-postbuild": "npm run build",
    "client": "react-scripts start",
    "server": "nodemon --watch server server/server.js",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

feedback.router.js

    const express = require('express');
    const router = express.Router();
    const pool = require('../modules/pool');

    // GET feedback
    router.get('/', (req, res) => {
        // Request all entered feedback and return them
        pool.query('SELECT * FROM feedback ORDER BY id DESC;')
            .then((result) => {
                res.send(result.rows);
            }).catch((error) => {
                console.log('Error GET /api/feedback', error);
                res.sendStatus(500);  
        });
    })

    // GET feedback
    router.get('/flagged', (req, res) => {
        // Request all entered feedback and return them
        pool.query('SELECT * FROM feedback WHERE flagged = true ORDER BY id DESC;')
            .then((result) => {
                res.send(result.rows);
            }).catch((error) => {
                console.log('Error GET /api/feedback/flagged', error);
                res.sendStatus(500);  
        });
    })

    // POST new feedback entry
    router.post('/', async (req, res) => {
        const client = await pool.connect();

        try {
            const {
                feeling,
                understanding,
                support,
                comments,
                flagged
            } = req.body;
            await client.query('BEGIN')
            const orderInsertResults = await client.query(`INSERT INTO feedback ("feeling","understanding","support","comments","flagged")
            VALUES ($1, $2, $3, $4, $5);`, [feeling, understanding, support, comments, flagged]);

            await client.query('COMMIT')
            res.sendStatus(201);
        } catch (error) {
            await client.query('ROLLBACK')
            console.log('Error post /api/feedback', error);
            res.sendStatus(500);
        } finally {
            client.release()
        }
    });

    // DELETE a feedback entry
    router.delete('/:id', (req, res) => {
        pool.query('DELETE FROM feedback WHERE id=$1', [req.params.id]).then((result) => {
            res.sendStatus(200);
        }).catch((error) => {
            console.log('Error delete /api/feedback', error);
            res.sendStatus(500);
        })
    });

    // PUT / update a feedback entry
    router.put('/:id', (req,res) => {
        let feedbackId = req.params.id;
        let updatedFlagStatus = req.body.updatedFlagStatus;
        console.log('to update flag of item',feedbackId,'to',updatedFlagStatus);
        const sqlText = `UPDATE feedback SET flagged = $2 WHERE id=$1`;
        console.log('sqlText:',sqlText);
        pool.query(sqlText,[feedbackId, updatedFlagStatus])
            .then( (result) => {
                console.log('successfully updated flag status', result);
                res.sendStatus(200);
            })
            .catch( (error) => {
                console.log('error updating flag status', error);
                res.sendStatus(500);
            })
    })

    module.exports = router;

1 个答案:

答案 0 :(得分:1)

每当您使用Express来服务React + ReactRouter应用时,都会遇到Express路由和React Router“冲突”的情况。

在生产环境中,您的Express服务器将“如果无法识别路由,则提供index.html文件” ,因此,当您请求/feedback时,第一行是app.get('*'...,这就是您的Ajax请求实际上返回index.html文件的原因。

if (process.env.NODE_ENV === 'production') {
    // Exprees will serve up production assets
    app.use(express.static(path.join(__dirname, 'build')));

    // Express serve up index.html file if it doesn't recognize route
    app.get('*', (req, res) => {
      res.sendFile(path.join(__dirname, 'build', 'index.html'));
    });
}

/** ---------- EXPRESS ROUTES ---------- **/
app.use('/feedback', feedbackRouter);

app.use('/feedback', feedbackRouter);行放在开头,它应该可以工作。

现在,您应该完全安装“ Heroku Toolbelt” https://devcenter.heroku.com/articles/heroku-cli,以便可以在终端上运行heroku logs -t以便调试服务器端代码。

希望有帮助!