【问题标题】:Unable to connect to Heroku's database using sequelize-typescript无法使用 sequelize-typescript 连接到 Heroku 的数据库
【发布时间】:2019-08-05 23:26:13
【问题描述】:

我使用 sequelize-typescript 的 Express API 无法连接到 Heroku 的 PostgreSQL 数据库。

通过运行以下命令初始化 Heroku 应用程序:

heroku create <my-app-name>
heroku addons:create heroku-postgresql:hobby-dev
git push heroku master

此应用程序在我的本地环境中运行没有问题。

我可以确认 DATABASE_URL 环境变量在 Heroku 上是正确的。

我的package.json 脚​​本似乎也是正确的:

"scripts": {
  "build": "tsc",
  "dev": "node_modules/.bin/nodemon",
  "postinstall": "npm run build",
  "start": "node dist/server/server.js"
}

我尝试解决的问题 从最重要到最不重要

  1. 通过heroku config:set 设置NPM_CONFIG_PRODUCTION=false。我在阅读了这个SO thread 之后做了这个,它指向了这个Heroku document。我认为这个想法是告诉 Heroku 跳过修剪 devDependencies 的步骤,以便 Heroku 可以将 TypeScript 文件编译成 Javascript。

  2. process.env.NODE_ENV === 'production' 时在我的Sequelize 连接中设置dialectOptions: { ssl: true }。我是在阅读了一些关于这个主题的 SO 文档后才这样做的。

  3. 使用用户名和密码字段提供 Sequelize 连接。我这样做了:

// In the terminal
heroku config:set DB_USER=<database user from Heroku database credentials>
heroku config:set DB_PASSWORD=<database password from Heroku database credentials>

// In Sequelize connection
export const connection = new Sequelize({
    dialect: 'postgres',
    protocol: 'postgres',
    username: process.env.DB_USER || '',
    password: process.env.DB_PASSWORD || '',
    database: process.env.DATABASE_URL || 'fitnius-db',
    logging: false,
    dialectOptions: { ssl },
    models: [__dirname + '/models', __dirname + '/models' + '/joins']
})
  1. @types/pg 添加为依赖项

  2. 删除我的 Heroku 应用并实例化一个新应用

  3. "exclude": [] 中的tsconfig.json 中删除"node_modules"

  4. nodemon.json删除所有环境变量

  5. 创建Procfile 并在其中添加web: node dist/server/server.js

  6. 在依赖项和 devDependencies 之间移动,@types/express@types/sequelize。我很绝望,并阅读了这个document from Sequelize

    • 另外,安装 @types/node@types/validator 作为依赖项
  7. 将构建脚本设置为"build": "tsc -p ." (不完全确定-p 标志的作用......但我做到了)

  8. 在我的启动脚本中设置已编译服务器文件的相对路径:

    • "start": "node ./dist/server/server.js"

问题:如何让 Sequelize 建立与 Heroku 的 PostgreSQL 数据库的连接并让我的应用程序运行?

以下是与问题相关的代码。


来自heroku logs --tail的错误日志

{ SequelizeConnectionRefusedError: connect ECONNREFUSED 127.0.0.1:5432
at connection.connect.err (/app/node_modules/sequelize/lib/dialects/postgres/connection-manager.js:170:24)
at Connection.connectingErrorHandler (/app/node_modules/pg/lib/client.js:191:14)
at Connection.emit (events.js:198:13)
at Socket.reportStreamError (/app/node_modules/pg/lib/connection.js:72:10)
at Socket.emit (events.js:198:13)
at emitErrorNT (internal/streams/destroy.js:91:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:59:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
name: 'SequelizeConnectionRefusedError',
parent:
{ Error: connect ECONNREFUSED 127.0.0.1:5432
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1106:14)
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 5432 },

at=error code=H10 desc="App crashed" method=GET path="/" 
host=fitnius-web-api.herokuapp.com 
request_id=c8c76ce3-8201-4733-99fb-bee4121b09d1 fwd="100.1.44.6" 
dyno= connect= service= status=503 bytes= protocol=https

续集连接

import { Sequelize } from 'sequelize-typescript'

const ssl = process.env.NODE_ENV === 'production'

export const connection = new Sequelize({
    dialect: 'postgres',
    protocol: 'postgres',
    database: process.env.DATABASE_URL || 'fitnius-db',
    logging: false,
    dialectOptions: { ssl },
    models: [__dirname + '/models', __dirname + '/models' + '/joins']
})

快递服务器

import app from './app'
import { connection } from '../database/connection'

const PORT = process.env.PORT || 3000
connection
    .sync()
    .then(() => {
        app.listen(PORT, () => console.log(`Server is running on port ${PORT}`))
    })
    .catch(err => console.log(err))

tsconfig.json

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "outDir": "dist",
    "strict": true,
    "declaration": true,
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "sourceMap": true,
    "lib": ["es6", "dom"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", ".vscode"]
}

package.json

{
  "name": "fitnius-server",
  "version": "1.0.0",
  "description": "",
  "main": "dist/server/server.js",
  "scripts": {
    "build": "tsc",
    "dev": "node_modules/.bin/nodemon",
    "postinstall": "npm run build",
    "start": "node dist/server/server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@types/express": "^4.17.0",
    "@types/graphql": "^14.2.3",
    "@types/pg": "^7.4.14",
    "@types/sequelize": "^4.28.4",
    "express": "^4.17.1",
    "express-graphql": "^0.9.0",
    "graphql": "^14.4.2",
    "pg": "^7.12.0",
    "reflect-metadata": "^0.1.13",
    "sequelize": "^5.12.3",
    "sequelize-typescript": "^1.0.0-beta.3"
  },
  "devDependencies": {
    "nodemon": "^1.19.1",
    "ts-node": "^8.3.0",
    "typescript": "^3.5.3"
  }
}

目录树

root
  dist (compiled by tsc)
  node_modules
  src
    database
      models
      connection.ts (Sequelize connection)
    server
      app.ts
      server.ts (Express server)
  nodemon.json
  tsconfig.json
  package.json

【问题讨论】:

    标签: typescript heroku heroku-postgres sequelize-typescript


    【解决方案1】:

    翻遍sequelize-typescriptnpm包后发现database参数并不是指整个数据库的url。

    我能够通过从 Heroku 的数据库 url 解析以下内容来解决问题。我用这个database url parser 作为我的解决方案。

    interface ParsedDatabaseOptions {
        protocol: string | undefined
        host: string | undefined
        username: string | undefined
        password: string | undefined
        database: string | undefined
    }
    

    在将解析器转换为粗略的 TypeScript 版本(可以在 here 找到)之后,我通过检查是否为 NODE_ENV === 'production' 创建了一个条件,并将我的数据库选项设置为:

    import { Sequelize } from 'sequelize-typescript'
    // parseDatabaseUrl is currently a wonky piece of code
    import parseDatabaseUrl from '../utils/parse-database-url'
    
    const optionsProduction = parseDatabaseUrl(process.env.DATABASE_URL)
    const optionsDevelopment = { database: <your local database> }
    
    // Create conditional Sequelize database options here
    const sequelizeOptions = process.env.NODE_ENV === 'production'
        ? optionsProduction
        : optionsDevelopment
    
    const connection = new Sequelize({
        dialect: 'postgres',
        logging: false,
        ...sequelizeOptions, // Spread options here
        models: ...
    })
    

    【讨论】:

      猜你喜欢
      • 2012-01-13
      • 2021-02-06
      • 2013-04-21
      • 2021-07-10
      • 1970-01-01
      • 2014-03-30
      • 2013-04-19
      • 2015-02-25
      • 1970-01-01
      相关资源
      最近更新 更多