Node.js Sequelize CLI、Postgres、Heroku产品类型错误[ERR_INVALID_ARG_TYPE]:错误;url";参数的类型必须为字符串。接收类型未定义

Node.js Sequelize CLI、Postgres、Heroku产品类型错误[ERR_INVALID_ARG_TYPE]:错误;url";参数的类型必须为字符串。接收类型未定义,node.js,postgresql,heroku,sequelize.js,Node.js,Postgresql,Heroku,Sequelize.js,我已经被这个错误困扰了几天了,所以我在这里寻找一些见解。我有一个PERN stack应用程序,这是我第一次尝试部署到Heroku。我的应用程序看起来很好。我的应用程序在本地开发时运行得非常好。我可以从react build运行它,为静态文件提供服务,我可以在两个端口上运行前端和后端,它可以正常工作。我认为问题也与Sequelize CLI如何解析Heroku在生产中设置的数据库URL配置变量有关。如果我记录process.env.DATABASE_URL,我将从Heroku获得URI字符串(在下

我已经被这个错误困扰了几天了,所以我在这里寻找一些见解。我有一个PERN stack应用程序,这是我第一次尝试部署到Heroku。我的应用程序看起来很好。我的应用程序在本地开发时运行得非常好。我可以从react build运行它,为静态文件提供服务,我可以在两个端口上运行前端和后端,它可以正常工作。我认为问题也与Sequelize CLI如何解析Heroku在生产中设置的数据库URL配置变量有关。如果我记录process.env.DATABASE_URL,我将从Heroku获得URI字符串(在下面的错误堆栈中注明)

  • 我确保PG插件配置正确
  • 我在.env文件和heroku仪表板中设置了所有配置变量
  • My node_模块、.env文件未提交到My repo
  • 我已经删除了node_模块和package-lock.json并重新安装了它们
  • 我已注销process.env.DATABASE_URL,它已成功记录URI
我不断得到这个错误堆栈:

enter code here2020-07-19T00:56:44.000000+00:00 app[api]: Build succeeded
2020-07-19T00:57:10.671364+00:00 heroku[web.1]: Starting process with command `npm start`
2020-07-19T00:57:14.245382+00:00 app[web.1]: 
2020-07-19T00:57:14.245410+00:00 app[web.1]: > locals@1.0.0 start /app
2020-07-19T00:57:14.245411+00:00 app[web.1]: > node server.js
2020-07-19T00:57:14.245411+00:00 app[web.1]: 

// this is the console.log(process.env.DATABASE_URL)
2020-07-19T01:09:25.213184+00:00 app[web.1]: postgres://<user>:<password><omitted-info>:<port>/<app>

2020-07-19T00:57:14.903836+00:00 app[web.1]: internal/validators.js:107
2020-07-19T00:57:14.903838+00:00 app[web.1]: throw new ERR_INVALID_ARG_TYPE(name, 'string', value);
2020-07-19T00:57:14.903839+00:00 app[web.1]: ^
2020-07-19T00:57:14.903839+00:00 app[web.1]: 
2020-07-19T00:57:14.903841+00:00 app[web.1]: TypeError [ERR_INVALID_ARG_TYPE]: The "url" argument must be of type string. Received type undefined
2020-07-19T00:57:14.903841+00:00 app[web.1]: at validateString (internal/validators.js:107:11)
2020-07-19T00:57:14.903841+00:00 app[web.1]: at Url.parse (url.js:155:3)
2020-07-19T00:57:14.903842+00:00 app[web.1]: at Object.urlParse [as parse] (url.js:150:13)
2020-07-19T00:57:14.903843+00:00 app[web.1]: at new Sequelize (/app/node_modules/sequelize/lib/sequelize.js:187:28)
2020-07-19T00:57:14.903843+00:00 app[web.1]: at Object.<anonymous> (/app/models/index.js:14:15)
2020-07-19T00:57:14.903844+00:00 app[web.1]: at Module._compile (internal/modules/cjs/loader.js:759:30)
2020-07-19T00:57:14.903844+00:00 app[web.1]: at Object.Module._extensions..js (internal/modules/cjs/loader.js:770:10)
2020-07-19T00:57:14.903845+00:00 app[web.1]: at Module.load (internal/modules/cjs/loader.js:628:32)
2020-07-19T00:57:14.903845+00:00 app[web.1]: at Function.Module._load (internal/modules/cjs/loader.js:555:12)
2020-07-19T00:57:14.903845+00:00 app[web.1]: at Module.require (internal/modules/cjs/loader.js:666:19)
2020-07-19T00:57:14.903846+00:00 app[web.1]: at require (internal/modules/cjs/helpers.js:16:16)
2020-07-19T00:57:14.903846+00:00 app[web.1]: at Object.<anonymous> (/app/server.js:11:16)
2020-07-19T00:57:14.903847+00:00 app[web.1]: at Module._compile (internal/modules/cjs/loader.js:759:30)
2020-07-19T00:57:14.903847+00:00 app[web.1]: at Object.Module._extensions..js (internal/modules/cjs/loader.js:770:10)
2020-07-19T00:57:14.903847+00:00 app[web.1]: at Module.load (internal/modules/cjs/loader.js:628:32)
2020-07-19T00:57:14.903848+00:00 app[web.1]: at Function.Module._load (internal/modules/cjs/loader.js:555:12)
2020-07-19T00:57:14.903848+00:00 app[web.1]: at Function.Module.runMain (internal/modules/cjs/loader.js:826:10)
2020-07-19T00:57:14.903849+00:00 app[web.1]: at internal/main/run_main_module.js:17:11
2020-07-19T00:57:14.915610+00:00 app[web.1]: npm ERR! code ELIFECYCLE
2020-07-19T00:57:14.916028+00:00 app[web.1]: npm ERR! errno 1
2020-07-19T00:57:14.917598+00:00 app[web.1]: npm ERR! locals@1.0.0 start: `node server.js`
2020-07-19T00:57:14.917834+00:00 app[web.1]: npm ERR! Exit status 1
2020-07-19T00:57:14.918113+00:00 app[web.1]: npm ERR!
2020-07-19T00:57:14.918349+00:00 app[web.1]: npm ERR! Failed at the locals@1.0.0 start script.
2020-07-19T00:57:14.918598+00:00 app[web.1]: npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
2020-07-19T00:57:14.952443+00:00 app[web.1]: 
2020-07-19T00:57:14.952709+00:00 app[web.1]: npm ERR! A complete log of this run can be found in:
2020-07-19T00:57:14.952798+00:00 app[web.1]: npm ERR!     /app/.npm/_logs/2020-07-19T00_57_14_920Z-debug.log
2020-07-19T00:57:15.047526+00:00 heroku[web.1]: Process exited with status 1
2020-07-19T00:57:15.094041+00:00 heroku[web.1]: State changed from starting to crashed
2020-07-19T00:57:15.951511+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET path="/" host=locals-deploy.herokuapp.com request_id=f27a1f1b-5d62-4d98-9383-6d5e46242789 fwd="71.92.89.136" dyno= connect= service= status=503 bytes= protocol=https
错误:

Running sequelize db:migrate on ⬢ locals-deploy... up, run.7436 (Free)

Sequelize CLI [Node: 12.0.0, CLI: 5.5.1, ORM: 5.22.3]

Loaded configuration file "config/config.js".
Using environment "production".

ERROR: Error parsing url: undefined

package.json

{
  "name": "locals",
  "version": "1.0.0",
  "description": "A place for travelers to meet locals.",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "heroku-postbuild": "cd client && npm install && npm run build"
  },
  "author": "Name Name",
  "license": "MIT",
  "dependencies": {
    "axios": "^0.19.2",
    "bcryptjs": "^2.4.3",
    "body-parser": "^1.19.0",
    "cloudinary": "^1.22.0",
    "config": "^3.3.1",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "express-fileupload": "^1.1.7-alpha.3",
    "express-validator": "^6.5.0",
    "jsonwebtoken": "^8.5.1",
    "nodemon": "^2.0.4",
    "pg": "^8.2.1",
    "pg-hstore": "^2.3.3",
    "sequelize": "^5.21.11",
    "sequelize-cli": "^5.5.1"
  },
  "engines": {
    "node": "12.0.0"
  }
}
server.js

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const PORT = process.env.PORT || 5000;

const upload = require('express-fileupload');
app.use(upload({useTempFiles: true}));

const cors = require('cors');
const path = require('path');
const models = require('./models');

// variable to enable global error logging
const enableGlobalErrorLogging =
  process.env.ENABLE_GLOBAL_ERROR_LOGGING === 'true';

// Enable All CORS Requests
app.use(cors());

//Init Middleware
app.use(bodyParser.json());
app.use(
  bodyParser.urlencoded({
    extended: true,
  })
);

//app.use(express.static(path.join(__dirname, 'client/build')));

console.log(process.env.NODE_ENV);
//if running in production mode then it serves static files from build in client
if (process.env.NODE_ENV === 'production') {
  //points to index.js in client
  app.use(express.static(path.join(__dirname, 'client/build')));
}

//Routes
app.use('/users', require('./routes/users'));
app.use('/auth', require('./routes/auth'));
app.use('/posts', require('./routes/posts'));
app.use('/api/profile', require('./routes/profile'));
app.use('/adventure', require('./routes/adventure'));
app.use('/review', require('./routes/review'));
app.use('/favorites', require('./routes/favorites'));
app.use('/upload', require('./routes/uploadImage'));

//catch all method redirects to build folder
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});

// send 404 if no other route matched
app.use((req, res) => {
  res.status(404).json({
    message: 'Route Not Found',
  });
});

// setup a global error handler
app.use((err, req, res, next) => {
  console.log('I am catching the error');
  if (enableGlobalErrorLogging) {
    console.error(`Global error handler: ${JSON.stringify(err.stack)}`);
  }
  if (err.name === 'SequelizeUniqueConstraintError') {
    return res.status(400).json({
      errors: ['Email for user already exists'],
    });
  }
  // if (err.name === 'SequelizeDatabaseError') {
  //   return res.status(404).json({errors: 'Oh no! Page not found.'});
  // }
  res.status(err.status || 500).json({
    message: err.message,
    name: err.name,
    error: {},
  });
});

//Sets Port and Listens
return models.sequelize.sync().then((result) => {
  app.listen(process.env.PORT || 5000, () => {
    console.log(`App running on port ${process.env.PORT || 5000}.`);
  });
});
Procfile

web: node server.js

package.json

{
  "name": "locals",
  "version": "1.0.0",
  "description": "A place for travelers to meet locals.",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "heroku-postbuild": "cd client && npm install && npm run build"
  },
  "author": "Name Name",
  "license": "MIT",
  "dependencies": {
    "axios": "^0.19.2",
    "bcryptjs": "^2.4.3",
    "body-parser": "^1.19.0",
    "cloudinary": "^1.22.0",
    "config": "^3.3.1",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "express-fileupload": "^1.1.7-alpha.3",
    "express-validator": "^6.5.0",
    "jsonwebtoken": "^8.5.1",
    "nodemon": "^2.0.4",
    "pg": "^8.2.1",
    "pg-hstore": "^2.3.3",
    "sequelize": "^5.21.11",
    "sequelize-cli": "^5.5.1"
  },
  "engines": {
    "node": "12.0.0"
  }
}
server.js

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const PORT = process.env.PORT || 5000;

const upload = require('express-fileupload');
app.use(upload({useTempFiles: true}));

const cors = require('cors');
const path = require('path');
const models = require('./models');

// variable to enable global error logging
const enableGlobalErrorLogging =
  process.env.ENABLE_GLOBAL_ERROR_LOGGING === 'true';

// Enable All CORS Requests
app.use(cors());

//Init Middleware
app.use(bodyParser.json());
app.use(
  bodyParser.urlencoded({
    extended: true,
  })
);

//app.use(express.static(path.join(__dirname, 'client/build')));

console.log(process.env.NODE_ENV);
//if running in production mode then it serves static files from build in client
if (process.env.NODE_ENV === 'production') {
  //points to index.js in client
  app.use(express.static(path.join(__dirname, 'client/build')));
}

//Routes
app.use('/users', require('./routes/users'));
app.use('/auth', require('./routes/auth'));
app.use('/posts', require('./routes/posts'));
app.use('/api/profile', require('./routes/profile'));
app.use('/adventure', require('./routes/adventure'));
app.use('/review', require('./routes/review'));
app.use('/favorites', require('./routes/favorites'));
app.use('/upload', require('./routes/uploadImage'));

//catch all method redirects to build folder
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});

// send 404 if no other route matched
app.use((req, res) => {
  res.status(404).json({
    message: 'Route Not Found',
  });
});

// setup a global error handler
app.use((err, req, res, next) => {
  console.log('I am catching the error');
  if (enableGlobalErrorLogging) {
    console.error(`Global error handler: ${JSON.stringify(err.stack)}`);
  }
  if (err.name === 'SequelizeUniqueConstraintError') {
    return res.status(400).json({
      errors: ['Email for user already exists'],
    });
  }
  // if (err.name === 'SequelizeDatabaseError') {
  //   return res.status(404).json({errors: 'Oh no! Page not found.'});
  // }
  res.status(err.status || 500).json({
    message: err.message,
    name: err.name,
    error: {},
  });
});

//Sets Port and Listens
return models.sequelize.sync().then((result) => {
  app.listen(process.env.PORT || 5000, () => {
    console.log(`App running on port ${process.env.PORT || 5000}.`);
  });
});
Procfile

web: node server.js
config.js

if (process.env.NODE_ENV !== 'production') require('dotenv').config();
//PG_HOST = 127.0.0.1

console.log(process.env.DATABASE_URL);
module.exports = {
  development: {
    username: process.env.PG_USER,
    password: process.env.PG_PASSWORD,
    database: process.env.PG_DATABASE,
    host: process.env.PG_HOST,
    dialect: 'postgres',
    port: process.env.PG_PORT,
    operatorsAliases: 0,
  },
  test: {
    username: process.env.PG_USER,
    password: process.env.PG_PASSWORD,
    database: process.env.PG_DATABASE,
    host: process.env.PG_HOST,
    dialect: 'postgres',
    port: process.env.PG_PORT,
    operatorsAliases: 0,
  },
  production: {
    use_env_variable: process.env.DATABASE_URL,
    dialect: 'postgres',
    dialectOptions: {
      ssl: true,
    },
  },
};

package.json

{
  "name": "locals",
  "version": "1.0.0",
  "description": "A place for travelers to meet locals.",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "heroku-postbuild": "cd client && npm install && npm run build"
  },
  "author": "Name Name",
  "license": "MIT",
  "dependencies": {
    "axios": "^0.19.2",
    "bcryptjs": "^2.4.3",
    "body-parser": "^1.19.0",
    "cloudinary": "^1.22.0",
    "config": "^3.3.1",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "express-fileupload": "^1.1.7-alpha.3",
    "express-validator": "^6.5.0",
    "jsonwebtoken": "^8.5.1",
    "nodemon": "^2.0.4",
    "pg": "^8.2.1",
    "pg-hstore": "^2.3.3",
    "sequelize": "^5.21.11",
    "sequelize-cli": "^5.5.1"
  },
  "engines": {
    "node": "12.0.0"
  }
}
server.js

const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const PORT = process.env.PORT || 5000;

const upload = require('express-fileupload');
app.use(upload({useTempFiles: true}));

const cors = require('cors');
const path = require('path');
const models = require('./models');

// variable to enable global error logging
const enableGlobalErrorLogging =
  process.env.ENABLE_GLOBAL_ERROR_LOGGING === 'true';

// Enable All CORS Requests
app.use(cors());

//Init Middleware
app.use(bodyParser.json());
app.use(
  bodyParser.urlencoded({
    extended: true,
  })
);

//app.use(express.static(path.join(__dirname, 'client/build')));

console.log(process.env.NODE_ENV);
//if running in production mode then it serves static files from build in client
if (process.env.NODE_ENV === 'production') {
  //points to index.js in client
  app.use(express.static(path.join(__dirname, 'client/build')));
}

//Routes
app.use('/users', require('./routes/users'));
app.use('/auth', require('./routes/auth'));
app.use('/posts', require('./routes/posts'));
app.use('/api/profile', require('./routes/profile'));
app.use('/adventure', require('./routes/adventure'));
app.use('/review', require('./routes/review'));
app.use('/favorites', require('./routes/favorites'));
app.use('/upload', require('./routes/uploadImage'));

//catch all method redirects to build folder
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});

// send 404 if no other route matched
app.use((req, res) => {
  res.status(404).json({
    message: 'Route Not Found',
  });
});

// setup a global error handler
app.use((err, req, res, next) => {
  console.log('I am catching the error');
  if (enableGlobalErrorLogging) {
    console.error(`Global error handler: ${JSON.stringify(err.stack)}`);
  }
  if (err.name === 'SequelizeUniqueConstraintError') {
    return res.status(400).json({
      errors: ['Email for user already exists'],
    });
  }
  // if (err.name === 'SequelizeDatabaseError') {
  //   return res.status(404).json({errors: 'Oh no! Page not found.'});
  // }
  res.status(err.status || 500).json({
    message: err.message,
    name: err.name,
    error: {},
  });
});

//Sets Port and Listens
return models.sequelize.sync().then((result) => {
  app.listen(process.env.PORT || 5000, () => {
    console.log(`App running on port ${process.env.PORT || 5000}.`);
  });
});
Procfile

web: node server.js
编辑 我做了一个bug报告,实际上我认为我可能已经修复了node_modules包中抛出错误的问题。现在,我必须弄清楚如何在Heroku内部进行更改,因为我们不提交node_模块来查看它是否有效。我现在可以在生产模式下本地运行它,而不会再现错误

如果有人感兴趣,请报告错误


在配置文件中尝试此操作

production: {
    use_env_variable: "DATABASE_URL",
    dialect: 'postgres',
    dialectOptions: {
      ssl: true,
    },
  },

由于您使用的是
use_env_variable
,因此您应该能够将变量的名称作为值。

,因为我的节点模块/sequelize包中出现了错误。我追溯到
/node\u modules/sequelize/lib/sequelize.js:187:28
。发生的情况是,我的配置文件正在从
process.env.DATABASE\u URL
提交生产下的URI字符串,并将其附加到
username
参数或索引1。问题是如何编写
url.parse
,以及传递什么参数。但是,如果用户提交它传递的数据库URL URI,就像它是一个数组一样,那么第一个参数始终是未定义的,因为它所附加的用户名是索引1。我将解析参数更改为
consturlparts=url.parse(options.use\u env\u variable,true)
这似乎解决了我所有的问题,因为直接获取要解析的URI,而不用担心索引值

constructor(database, username, password, options) {
    let config;

    if (arguments.length === 1 && typeof database === 'object') {
      // new Sequelize({ ... options })
      options = database;
      config = _.pick(options, 'host', 'port', 'database', 'username', 'password');
    } else if (
      (arguments.length === 1 && typeof database === 'string') ||
      (arguments.length === 2 && typeof username === 'object')
    ) {
      // new Sequelize(URI, { ... options })   <--this was already commented out

      config = {};
      options = username || {};

      // url.parse wants to access the object like an array, however, first item is always undefined and it 
      // needs to access the use_env_variable, which is attached to username argument
     // const urlParts = url.parse(options.use_env_variable, true);

      const urlParts = url.parse(arguments[0], true);

      options.dialect = urlParts.protocol.replace(/:$/, '');
      options.host = urlParts.hostname;
...
构造函数(数据库、用户名、密码、选项){
让配置;
if(arguments.length==1&&typeof数据库==='object'){
//新的续集({…选项})
选项=数据库;
config=uux.pick(选项“主机”、“端口”、“数据库”、“用户名”、“密码”);
}否则如果(
(arguments.length==1&&typeof数据库==='string')||
(arguments.length==2&&typeof username==='object')
) {

//新的续集(URI,{…选项})嘿,谢谢你的快速响应。我已经尝试过做你的解决方案,并将配置文件重新配置为.json。仍然不走运。我一直抛出相同的错误。如果我不使用括号,也不使用process.env。我抛出一个类型错误,无法读取数据库URL。如果我手动将其设置为NODE,我还能够在本地重现错误NV到生产环境,并对生产环境下的URL进行硬编码。