Heroku - web.1:在node.js应用程序中崩溃

时间:2018-01-30 13:40:29

标签: javascript node.js express heroku

所以我第一次尝试在heroku中部署我的node.js应用程序。

部署我的代码并进入heroku部署指南中的第6步后:https://devcenter.heroku.com/articles/getting-started-with-nodejs#scale-the-app

它告诉我它已部署好了所以我打开了#34;应用程序错误" - 浏览器控制台为503

接下来,我在项目中添加了 Procfile ,重新部署,然后运行heroku ps顶部,返回以下内容:

=== web (Free): yarn start:production (1)
web.1: crashed 2018/01/30 13:17:05 +0000 (~ 5m ago)

我不太确定从哪里开始,因为heroku指南不会解释如果我遇到此错误该怎么办。

这是我的node.js app的最初几页:

的package.json

{
  "name": "",
  "version": "2.5.1",
  "description": "",
  "main": "index.js",
  "engines": {
    "node": ">=6.0",
    "npm": ">=3.0"
  },
  "repository": {
    "type": "git",
    "url": ""
  }
  "author": "",
  "license": "",
  "bugs": {
    "url": ""
  },
  "homepage": "",
  "scripts": {
    "start": "better-npm-run start",
    "start:production": "yarn build && yarn start:prod",
    "start:prod": "better-npm-run start:prod",
    "build": "yarn clean:build && better-npm-run build",
    "lint": "yarn lint:js && yarn lint:style",
    "lint:js": "better-npm-run lint:js",
    "lint:style": "better-npm-run lint:style",
    "flow": "better-npm-run flow",
    "test": "better-npm-run test",
    "test:watch": "yarn test --watch",
    "clean:all": "yarn clean:build && yarn clean:test",
    "clean:build": "better-npm-run clean:build",
    "clean:test": "better-npm-run clean:test",
    "coveralls": "better-npm-run coveralls && yarn clean:test"
  },
  "betterScripts": {
    "start": {
      "command": "nodemon ./index.js",
      "env": {
        "NODE_PATH": "./src",
        "NODE_ENV": "development",
        "PORT": 3000
      }
    },
    "start:prod": {
      "command": "node ./index.js",
      "env": {
        "NODE_PATH": "./src",
        "NODE_ENV": "production",
        "PORT": 8080
      }
    },
    "build": {
      "command": "webpack --progress --hide-modules --config ./tools/webpack/config.babel.js",
      "env": {
        "NODE_ENV": "production"
      }
    },
    "lint:js": {
      "command": "eslint ./src ./tools ./index.js"
    },
    "lint:style": {
      "command": "stylelint \"./src/**/*.scss\" --syntax scss"
    },
    "flow": {
      "command": "flow; test $? -eq 0 -o $? -eq 2"
    },
    "test": {
      "command": "jest --coverage",
      "env": {
        "NODE_ENV": "test"
      }
    },
    "clean:build": {
      "command": "rimraf ./public/assets"
    },
    "clean:test": {
      "command": "rimraf ./coverage"
    },
    "coveralls": {
      "command": "cat ./coverage/lcov.info | coveralls"
    }
  },
  "babel": {
    "presets": [
      "env",
      "react",
      "stage-0"
    ],
    "env": {
      "production": {
        "plugins": [
          "transform-remove-console"
        ]
      }
    }
  },
  "eslintConfig": {
    "parser": "babel-eslint",
    "extends": "airbnb",
    "plugins": [
      "react",
      "jsx-a11y",
      "import"
    ],
    "env": {
      "browser": true,
      "node": true,
      "jest": true,
      "es6": true
    },
    "rules": {
      "linebreak-style": 0,
      "global-require": 0,
      "no-underscore-dangle": 0,
      "no-console": 0,
      "react/jsx-filename-extension": [
        1,
        {
          "extensions": [
            ".js",
            ".jsx"
          ]
        }
      ],
      "import/no-extraneous-dependencies": [
        "error",
        {
          "devDependencies": true
        }
      ],
      "function-paren-newline": 0
    },
    "globals": {
      "__CLIENT__": true,
      "__SERVER__": true,
      "__DISABLE_SSR__": true,
      "__DEV__": true,
      "webpackIsomorphicTools": true
    }
  },
  "stylelint": {
    "extends": "stylelint-config-standard",
    "rules": {
      "string-quotes": "single",
      "selector-pseudo-class-no-unknown": [
        true,
        {
          "ignorePseudoClasses": [
            "global",
            "local"
          ]
        }
      ]
    }
  },
  "browserslist": [
    "last 2 versions",
    "not ie <= 8"
  ],
  "jest": {
    "setupFiles": [
      "raf/polyfill",
      "<rootDir>/tools/jest/setup.js"
    ],
    "collectCoverageFrom": [
      "src/containers/**/*.js",
      "src/components/**/*.js",
      "!src/**/__tests__"
    ],
    "moduleNameMapper": {
      ".*\\.(css|scss|sass)$": "<rootDir>/tools/jest/styleMock.js",
      ".*\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/tools/jest/assetMock.js"
    }
  }
}

index.js

/* @flow */

// Use babel-register to precompile ES6 syntax
require('babel-core/register');

const WebpackIsomorphicTools = require('webpack-isomorphic-tools');

// Setup global variables for server
global.__CLIENT__ = false;
global.__SERVER__ = true;
global.__DISABLE_SSR__ = false; // Disable server side render here
global.__DEV__ = process.env.NODE_ENV !== 'production';

// This should be the same with webpack context
const dirRoot = require('path').join(process.cwd());

// Settings of webpack-isomorphic-tools
global.webpackIsomorphicTools =
  new WebpackIsomorphicTools(require('./tools/webpack/WIT.config')).server(dirRoot, () => require('./src/server'));

WIT.config.js

const WebpackIsomorphicToolsPlugin = require('webpack-isomorphic-tools/plugin');

module.exports = {
  // debug: true,
  // webpack_assets_file_path: 'webpack-assets.json',
  // webpack_stats_file_path: 'webpack-stats.json',
  assets: {
    images: {
      extensions: ['png', 'jpg', 'jpeg', 'gif'],
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
    },
    fonts: {
      extensions: ['eot', 'ttf', 'woff', 'woff2'],
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
    },
    svg: {
      extension: 'svg',
      parser: WebpackIsomorphicToolsPlugin.url_loader_parser,
    },
    style_modules: {
      extensions: ['css', 'scss'],
      filter: (module, regex, options, log) => {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.style_loader_filter(module, regex, options, log);
        }

        return regex.test(module.name);
      },
      path: (module, options, log) => {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.style_loader_path_extractor(module, options, log);
        }

        return module.name;
      },
      parser: (module, options, log) => {
        if (options.development) {
          return WebpackIsomorphicToolsPlugin.css_modules_loader_parser(module, options, log);
        }

        return module.source;
      },
    },
  },
};

server.js

   /* @flow */

import path from 'path';
import morgan from 'morgan';
import express from 'express';
import compression from 'compression';
import helmet from 'helmet';
import hpp from 'hpp';
import favicon from 'serve-favicon';
import React from 'react';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import { StaticRouter, matchPath } from 'react-router-dom';
import { Provider } from 'react-redux';
import chalk from 'chalk';

import createHistory from 'history/createMemoryHistory';
import configureStore from './redux/store';
import Html from './utils/Html';
import App from './containers/App';
import routes from './routes';
import { port, host } from './config';

const app = express();

app.set('port', process.env.PORT || 3000);

// Using helmet to secure Express with various HTTP headers
app.use(helmet());
// Prevent HTTP parameter pollution.
app.use(hpp());
// Compress all requests
app.use(compression());

// Use morgan for http request debug (only show error)
app.use(morgan('dev', { skip: (req, res) => res.statusCode < 400 }));
app.use(favicon(path.join(process.cwd(), './public/favicon.ico')));
app.use(express.static(path.join(process.cwd(), './public')));

// Run express as webpack dev server
if (__DEV__) {
  const webpack = require('webpack');
  const webpackConfig = require('../tools/webpack/config.babel');

  const compiler = webpack(webpackConfig);

  app.use(require('webpack-dev-middleware')(compiler, {
    publicPath: webpackConfig.output.publicPath,
    hot: true,
    noInfo: true,
    stats: { colors: true },
    serverSideRender: true,
  }));

  app.use(require('webpack-hot-middleware')(compiler));
}

//GET week
app.get('/api/week', (req, res) => {
    console.log('week');

    var articles = [];

    db.collection('articles')
        .find()
        .limit(2)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET articles
app.get('/api/articles', (req, res) => {
    console.log('articles');

    var articles = [];

    db.collection('articles')
        .find()
        .limit(12)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET authorArticles
app.get('/api/authorArticles', (req, res) => {
    console.log('authorArticles');

    var articles = [];

    var ObjectId = require('mongodb').ObjectID;
    var author = {};
    var param = req.query.authorQuery;
    param = param.replace(/-/g, ' ');

    db.collection('articles')
        // .find()
        .find({"author" : {$regex : ".*" + param + ".*"}})
        .limit(12)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET extra
app.get('/api/extra', (req, res) => {
    console.log('extra');

    var articles = [];

    db.collection('articles')
        .aggregate([{ $sample: { size: 4 } }])
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET authors
app.get('/api/authors', (req, res) => {
    console.log('authors');

    var authors = [];

    db.collection('authors')
        .find()
        .limit(24)
        .toArray()
        .then(result => {
            // console.log(result);
            authors = authors.concat(result);
        }).then(() => {
            res.send(authors);
        }).catch(e => {
            console.error(e);
        });

});

//GET search
app.get('/api/search', (req, res) => {
    console.log('/api/search');

    var articles = [];

    db.collection('articles')
        .find({$or:[
                {title: {$regex : ".*" + req.query.searchQuery + ".*"}},
                {description: {$regex : ".*" + req.query.searchQuery + ".*"}},
                {author: {$regex : ".*" + req.query.searchQuery + ".*"}},
                {keywords: {$regex : ".*" + req.query.searchQuery + ".*"}}
              ]})
        .limit(24)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET category
app.get('/api/category', (req, res) => {
    console.log('category');

    var articles = [];

    db.collection('articles')
        .find({$or:[
                {category: {$regex : ".*" + req.query.categoryQuery + ".*"}}
              ]})
        .limit(12)
        .sort("date", -1)
        .toArray()
        .then(result => {
            articles = articles.concat(result);
        }).then(() => {
            // console.log(articles);
            res.send(articles);
        }).catch(e => {
            console.error(e);
        });

});

//GET article
app.get('/api/article', (req, res) => {
    console.log('article');

    var ObjectId = require('mongodb').ObjectID;
    var article = {};
    var param = req.query.title;
    param = param.replace(/-/g, ' ');

    db.collection('articles')
        .findOne({"title": param})
        .then(result => {
            article = result;
        }).then(() => {
            res.send(article);
        }).catch(e => {
            console.error(e);
        });

});

//GET author
app.get('/api/author', (req, res) => {
    console.log('author');

    var ObjectId = require('mongodb').ObjectID;
    var article = {};
    var param = req.query.title;
    param = param.replace(/-/g, ' ');

    db.collection('authors')
        .findOne({"name": param})
        .then(result => {
            article = result;
        }).then(() => {
            res.send(article);
        }).catch(e => {
            console.error(e);
        });

});

// Register server-side rendering middleware
app.get('*', (req, res) => {
  if (__DEV__) webpackIsomorphicTools.refresh();

  const history = createHistory();
  const store = configureStore(history);
  const renderHtml = (store, htmlContent) => { // eslint-disable-line no-shadow
    const html = renderToStaticMarkup(<Html store={store} htmlContent={htmlContent} />);

    return `<!doctype html>${html}`;
  };

  // If __DISABLE_SSR__ = true, disable server side rendering
  if (__DISABLE_SSR__) {
    res.send(renderHtml(store));
    return;
  }

  // Load data on server-side
  const loadBranchData = () => {
    const promises = [];

    routes.some((route) => {
      const match = matchPath(req.path, route);

      // $FlowFixMe: the params of pre-load actions are dynamic
      if (match && route.loadData) promises.push(route.loadData(store.dispatch, match.params));

      return match;
    });

    return Promise.all(promises);
  };

  // Send response after all the action(s) are dispathed
  loadBranchData()
    .then(() => {
      // Setup React-Router server-side rendering
      const routerContext = {};
      const htmlContent = renderToString(
        <Provider store={store}>
          <StaticRouter location={req.url} context={routerContext}>
            <App />
          </StaticRouter>
        </Provider>,
      );

      // Check if the render result contains a redirect, if so we need to set
      // the specific status and redirect header and end the response
      if (routerContext.url) {
        res.status(301).setHeader('Location', routerContext.url);
        res.end();

        return;
      }

      // Checking is page is 404
      const status = routerContext.status === '404' ? 404 : 200;

      // Pass the route and initial state into html template
      res.status(status).send(renderHtml(store, htmlContent));
    })
    .catch((err) => {
      res.status(404).send('Not Found :(');

      console.error(`==>   Rendering routes error: ${err}`);
    });
});

// connect to mongo db
var db
const MongoClient = require('mongodb').MongoClient
MongoClient.connect('mongodb://dannyjones360:test@ds123930.mlab.com:23930/halftimefront', (err, database) => {
    if (err) return console.log(err);
    db = database
    console.log('db connected');
})

if (port) {
  app.listen(port, host, (err) => {
    const url = `http://${host}:${port}`;

    if (err) console.error(`==>   OMG!!! ${err}`);

    console.info(chalk.green(`==>   Listening at ${url}`));

    // Open Chrome
    require('../tools/openBrowser')(url);
  });
} else {
  console.error(chalk.red('==>   OMG!!! No PORT environment variable has been specified'));
}

配置

module.exports = {
  host: 3000 || 'localhost', // Define your host from 'package.json'
  port: 3000,
  app: {
    htmlAttributes: { lang: 'en' },
    title: 'Rendah',
    titleTemplate: 'Rendah - %s',
    meta: [
      {
        name: 'description',
        content: 'Beats culture magazine',
      },
      {
        name: 'apple-mobile-web-app-title',
        content: 'Vernacare',
      },
      {
        name: 'apple-mobile-web-app-capable',
        content: 'yes',
      },
      {
        name: 'apple-mobile-web-app-status-bar-style',
        content: 'black',
      },
      {
        name: 'theme-color',
        content: '#ffffff',
      },
      {
        name: 'mobile-web-app-capable',
        content: 'yes',
      },
      {
        name: 'theme-color',
        content: '#fff',
      },
    ],
  },
};

任何帮助或建议将不胜感激 - 谢谢你提前。

在对Yoni Rabinovitch的答案做出弥补后,我部署了该网站,现在得到:

2018-02-05T11:37:12.562907+00:00 heroku[web.1]: Process exited with status 1
2018-02-05T11:37:12.580445+00:00 heroku[web.1]: State changed from starting to crashed
2018-02-05T11:37:15.775044+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=d7e4d005-d2f9-4c5f-89c8-14f2addc9ebf fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:16.157734+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=0f2a7123-f9bf-4ee0-bbc6-59894e21cc1b fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:19.664289+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=b3748306-5b3a-4dd6-be2c-58a171bafbd1 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:19.898230+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=99b155b8-17e9-47da-a454-d3d4c6f45ef4 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:21.262972+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=sleepy-scrubland-78530.herokuapp.com request_id=ca84a061-f834-476f-a269-7a9a8cd4adda fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https
2018-02-05T11:37:21.537896+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/favicon.ico" host=sleepy-scrubland-78530.herokuapp.com request_id=9e6e9096-f6b4-4d73-b0c1-faf921ea8666 fwd="185.108.171.221" dyno= connect= service= status=503 bytes= protocol=https

3 个答案:

答案 0 :(得分:2)

您似乎在package.json中设置了PORT env var。你不应该为Heroku这样做。 Heroku会自动为您设置。 相反,在server.js中添加类似的东西:

    app.set('port', process.env.PORT || 3000);

您随后可以调用app.listen(app.get(&#39; port&#39;),...)

答案 1 :(得分:0)

尝试使用 Procfile npm run start:production而不是使用纱线。有一次我在Heroku中遇到了相同的 App崩溃,因为在使用yarn调用run脚本时,它没有使用process全局变量。

在最新的部署中,我没有遇到这个问题,但它可能会与你发生争执。

答案 2 :(得分:0)

我假设你正在部署一个新的/示例应用程序。 你可以在上面尝试同样的过程:)

Heroku NodeJs sample app