繁体   English   中英

mongoose post.save 在 heroku 上失败,适用于本地主机

[英]mongoose post.save failing on heroku, works on localhost

我试图通过节点、快递、mongoose 和 heroku 简单地发布到我的 MongoDB Atlas db。 一个 Postman POST 请求,带有正文的原始 JSON:

{
    "title": "heroku post",
    "description": "post me plsssss"
}

使用这个确切的代码在本地主机上工作,但是当通过 heroku 上传时,try/catch 块在post.save()失败,因为响应是错误。

{
    "error": "there's an error",
    "message": {}
}

但是错误是空的,我不确定如何调试它。 我已经输入了mongoose.set('debug', true); app.js中,我修改了我的 package.json: "start": "node app.js DEBUG=mquery",但那些没有额外的 Z78E6221F6393D1356681DB398F14CE6 看到。 有没有其他方法可以知道为什么 post.save() 会引发错误,一些我没有使用的日志..以及如何查看这些日志? 或者,如果您只知道问题所在?

应用程序.js

//use dotenv to store secret keys
require("dotenv").config();
const express = require('express');
const mongoose = require('mongoose');
const app = express();
const cors = require('cors');

//connect to DB
mongoose.connect("mongodb+srv://grushevskiy:intercom@cluster-rest.4luv0.mongodb.net/cluster-rest?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, dbName: "cluster-rest" }, () => {
  console.log('connected to DB!')
})

mongoose.set('debug', true);

const db = mongoose.connection;

db.once('open', () => {
    console.log('connection opened')
});


//import routes for middleware
const postsRoute = require('./routes/posts');

//midleware routes
app.use('/posts', postsRoute)

//ROUTES
app.get('/', (req,res) => {
  res.send('we are on home')
})


//MIDDLEWARES
//cors
app.use(cors());
//decode url special characters
app.use(express.urlencoded({ extended: true }));
//parse json POSTs
app.use(express.json());


//How do we start listening to the server
app.listen( process.env.PORT || 3000);

帖子.js

const express = require ('express')
const router = express.Router();
const Post = require('../models/Post')

//SUBMIT A POST
router.post('/', async (req,res) => {
  const post = new Post({
    title: req.body.title,
    description: req.body.description
  });

  console.log(post)

  try {
    const savedPost = await post.save();
    res.json(savedPost);
    console.log(savedPost)
  } catch (err) {
    res.json({ error: "there's an error", message: err, })
  }
})

module.exports = router;

Post.js Model

const mongoose = require('mongoose')
const PostSchema = mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  description: {
    type: String,
    required: true
  },
  date: {
    type: Date,
    default: Date.now
  }
})
module.exports = mongoose.model('Post', PostSchema)

当我输入heroku logs --tail时没有错误,最初也是“连接到数据库”。 消息来得有点晚。? 我想知道这是否是异步/等待的问题。 我的 package:json:

{
  "name": "22-npmexpressrestapi",
  "version": "1.0.0",
  "engines": {
    "node": "14.15.3",
    "npm": "6.14.9"
  },
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js DEBUG=mquery",
    "start:dev": "node app.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "express": "^4.17.1",
    "nodemon": "^2.0.7"
  },
  "dependencies": {
    "dotenv": "^8.2.0",
    "express": "4.17.1",
    "cors": "^2.8.5",
    "mongoose": "^5.11.11"
  }
}

仔细阅读您的问题后,我有一些建议,我认为您可能想尝试一下。 首先,让我解释一下自己:

In my experience, when one learns how to build REST APIs with Node.js, using mongoose to communicate with a MongoDB cluster, this is what the sequence of events of their index.js file looks like:

  1. 执行一个 function 使用环境变量建立与数据库集群的连接。 此 function 仅运行一次并填充应用程序将与为其设计的任何模型一起使用的 de mongoose 实例。
  2. 通过要求适当的 package 来设置应用程序,定义它需要的任何中间件,并调用为其定义的所有路由。
  3. 在应用程序整合了正常运行所需的所有内容后,app.listen() 被调用,提供了一个有效的端口,然后......瞧。 你已经让你的服务器运行了。

当应用程序和数据库足够简单时,这就像一个魅力。 我已经使用这些相同的步骤构建了多个服务并将它们投入生产,而没有注意到 mongoose 和应用程序之间存在任何错误通信。 但是,如果您检查您提供的 App.js 代码,您会发现您的情况有所不同:您只有在设置应用程序、它的中间件和它的路由之后才连接到您的 Mongo 集群。 如果其中任何一个依赖于 mongoose 实例或要运行的模型,则很有可能当 Heroku 的编译器到达您的路由需要连接到数据库的地步时,它根本没有实现该连接(意味着尚未运行 mongoose.connect() 部分)喷射。

简单的解决方案

我认为 Heroku 运行整个代码的时间比本地机器长一点。 此外,如果您的本地版本连接到本地存储的 MongoDB,则很有可能比在云服务中运行得更快。 你的陈述

'连接到数据库! 消息来的有点晚

给了我希望,情况可能就是这样。 如果是这样,那我猜那是移动

mongoose.connect("mongodb+srv://xxxxx:xxxxx@cluster-rest.4luv0.mongodb.net/cluster-rest?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, dbName: "cluster-rest" }, () => {console.log('connected to DB;')});

App.js的第二行,在你调用 Dotenv 之后,就可以了。 您的 mongoose 实例将 go 进入已经与数据库和 App 将要使用的模型连接的 App。

异步解决方案

即使我之前写的内容解决了您的问题,我也想扩展解释,因为根据我的经验,该版本的解决方案也不正确。 我在这个答案开头暴露的做事方式是好的......只要你保持你的 MongoDB 集群和你的 mongoose 实例简单。 不久前,我不得不实现一个涉及更复杂数据库模式的服务,同一个 App 使用多个不同的数据库,并且它的许多路由直接取决于这些数据库的模型。

当我尝试使用我之前描述的逻辑来解决这样一个问题时,涉及到大量填充的数据库和 mongoose 实例中包含的几个模型,我意识到与连接到 mongoose 相比,Node 构建应用程序、它的中间件和它的路由要少得多并加载同一个应用程序运行所需的所有模型。 这意味着在实际连接数据库之前,我的Server connected to PORT ****消息。 这造成了麻烦。

这让我意识到,正确做事的唯一方法是确保异步性,只有在所有数据库和模型都加载到 mongoose 实例中并为其提供相同的实例后,才强制 App 运行。 这样,我最终得到了一个如下所示的index.js

 const Dotenv = require("dotenv").config(); const { connectMongoose } = require("./server/db/mongoose"); const wrappedApp = require("./app"); connectMongoose().then((mongoose) => { const App = wrappedApp(mongoose); App.listen(process.env.PORT, () => { console.log( `Hello, I'm your server and I'm working on port ${process.env.PORT}` ); }); });

一个包含多个函数的文件,用于管理与我的数据库和模型的连接,名为mongoose.js 以正确顺序实现所有连接的 function 看起来是:

 const connectMongoose = async (mongoose = require("mongoose")) => { try { // Close any previous connections await mongoose.disconnect(); // Connect the Main database console.log( "--> Loading databases and models from MongoDB. Please don't use our server jet. <--" ); mongoose = await connectMother(mongoose); // Connect all the client databases mongoose = await connectChildren(mongoose); console.log( "--> All databases and models loaded correctly. You can work now. <--" ); return mongoose; } catch (e) { console.error(e); } }; module.exports = { connectMongoose };

有了这个,文件app.js会返回一个 function ,需要为它提供一个 mongoose 实例并设置所有 Express 环境:

 module.exports = (Mongoose) => { const Express = require("express"); //Enrouting // Other required packages go here // EXPRESS SETTINGS const App = Express(); App.set("port", process.env.PORT || 3000); //Use port from cloud server // All the middleware App needs App.use(Flash()); // Routing: load your routes // Return fully formed App return App; };

只有使用这种模式,我才能确保事件链有意义:

  1. 连接所有数据库并加载它们的模型。
  2. 只有在最后一个数据库已经连接并且它的最后一个 model 被加载后,才能设置应用程序、它的中间件和你的路由。
  3. 使用 App.listen() 服务应用程序。

如果您的数据库不是很大,那么答案的第一部分可能会起作用。 但了解整个故事总是有用的。

当我添加错误的连接字符串时,我可以使用您的代码获得一个空的错误消息。

此回调中的 console.log 不正确:

mongoose.connect("mongodb+srv://xxxxx:xxxxx@cluster-rest.4luv0.mongodb.net/cluster-rest?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, dbName: "cluster-rest" }, () => {
  console.log('connected to DB!')
})

如果您想知道您是否已连接到 db,请使用以下命令:

mongoose.connect("mongodb+srv://xxxxx:xxxxx@cluster-rest.4luv0.mongodb.net/cluster-rest?retryWrites=true&w=majority", { useNewUrlParser: true, useUnifiedTopology: true, dbName: "cluster-rest" });

const db = mongoose.connection;

db.once('open', () => {
    console.log('connection opened')
});

我注意到您正在使用dotenv ,也许您没有向 heroku 主机添加变量。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM