【问题标题】:Express: Route is not created inside async functionExpress:路由不是在异步函数中创建的
【发布时间】:2021-12-14 01:56:32
【问题描述】:

这是创建测试路由的 api.js 模块:

'use strict';

module.exports = function (app) {
  
  console.log("before route creation");
  app.get("/api/test", (req, res) => {
    res.send("it worked");
  });
  console.log("routes created");
};

在 server.js 文件中,我将此模块导入为apiRoutes。然后,我在异步函数中调用它。

const databaseConnection = async (apiRoutes, app) => {
  try {
    await mongoose.connect(`mongodb+srv://replitUser:${process.env.DB_PW}@issuetracker.pbbm6.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`);
    console.log("db connection successful");

    //Routing for API 
    console.log("apiRoutes called");
    apiRoutes(app);  

  } catch (err) {
    console.log("an err occurred", err);
  }
}
databaseConnection(apiRoutes, app);
// apiRoutes(app);

字符串"before route creation""routes created" 被记录到控制台。但是,尽管没有发生错误,但该路由似乎不起作用。

如果我在异步函数之外调用apiRoutes,就像这里:

const databaseConnection = async (apiRoutes, app) => {
  try {
    await mongoose.connect(`mongodb+srv://replitUser:${process.env.DB_PW}@issuetracker.pbbm6.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`);
    console.log("db connection successful");

    //Routing for API 
    // console.log("apiRoutes called");
    // apiRoutes(app);  

  } catch (err) {
    console.log("an err occurred", err);
  }
}
databaseConnection(apiRoutes, app);
apiRoutes(app);

...它将成功创建测试路线。

我尝试直接在 async 函数内部而不是在新模块中创建路由,它什么也没改变,仍然没有创建路由。

const databaseConnection = async (apiRoutes, app) => {
  try {
    await mongoose.connect(`mongodb+srv://replitUser:${process.env.DB_PW}@issuetracker.pbbm6.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`);
    console.log("db connection successful");

    //Routing for API 
    // console.log("apiRoutes called");
    // apiRoutes(app);  
    app.get("/api/test", (req, res) => {
      res.send("it worked");
    });
  } catch (err) {
    console.log("an err occurred", err);
  }
}
databaseConnection(apiRoutes, app);

为什么我不能在异步函数中创建路由?

Here is a link to the project on replit - Feel free to fork

【问题讨论】:

  • 为什么不简单地制作 server.js 将连接到 db 然后基于 express 实例化应用程序?
  • 警告app.route('/:project/').get(...) 注册了一个通配符路由,它将匹配所有顶级路由。这通常是一种不好的做法,并且可能会导致问题,因为它甚至会匹配像 /contacts/help 等简单的东西,您不希望将其作为项目名称,因为您的前端可能想要使用各种其设计中的顶级 URL。使用app.get("/project/:project", ...) 会更安全,因为它会为您的项目 URL 创建一个特殊的 URL 命名空间,以便您的应用可以使用顶级 URL。

标签: javascript node.js express async-await


【解决方案1】:

我知道这不是您问题的直接答案。

但问题是你不能正确地构造你的代码。

所以在下面你可以看到应用程序结构具有单独的数据库和应用程序模块,应用程序在数据库连接后开始侦听。

server.js

const http = require('http');

const db = require('./db');
const app = require('./app');

const server = http.createServer(app);
const PORT = process.env.PORT || 8000;

(async () => {
  await db.connect();
  console.log('connected to db');

  server.listen(PORT, () => {
    console.log(`app listening at port: ${PORT}`);
  });      
})();

db.js

const mongoose = require('mongoose');

const UserSchema = require('./schemas/User');
mongoose.model('User', UserSchema);

module.exports = {
  connect: function() {
    const dsn = `mongodb+srv://replitUser:${process.env.DB_PW}@issuetracker.pbbm6.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`;
    return mongoose.connect(dsn);
  },
  model: function(name) {
    return mongoose.model(name);
  },
};

app.js

const express = require('express');
const app = express();

const routes = require('./routes');
app.use(routes);

module.exports = app;

路由/index.js

const express = require('express');
const router = express.Router();

const users = require('./users');
router.use('/api/users', users);

module.exports = router;

路由/users.js

const express = require('express');
const router = express.Router();

const db = require('../db');
const User = db.model('User');

router.get('/', async (req, res) => {
  const users = await User.find({}).lean();
  res.status(200).send({users});
});

router.get('/:id', async (req, res) => {
  const user = await User.findById(req.params.id).lean();
  if (!user) {
    return res.status(404).end();
  }
  res.status(200).send(user);
});

module.exports = router;

架构/User.js

const mongoose = require('mongoose');
const {Schema} = mongoose;

const UserSchema = new Schema({
  username: Schema.Types.String,
  password: Schema.Types.String,
  name: Schema.Types.String,
});

module.exports = UserSchema;

【讨论】:

    【解决方案2】:

    起初,我认为使用express.Router() 很容易解决。 这就是它的样子:

    创建路由器并将其挂载到/api路径:

    const router = express.Router();
    app.use("/api", router);
    

    然后,使用router.get() 而不是app.get() 创建路由。

    const databaseConnection = async (router) => {
      try {
        await mongoose.connect(`mongodb+srv://replitUser:${process.env.DB_PW}@issuetracker.pbbm6.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`);
        console.log("db connection successful");
    
        //Routing for API 
        router.get("/test", (req, res) => {
          res.send("it worked");
        });
      } catch (err) {
        console.log("an err occurred", err);
      }
    }
    databaseConnection(router);
    

    Here is a link to the complete version of this

    但正如用户@num8er 提到的,这种结构是不好的做法,没有必要。

    我不明白有连接数据库后不需要创建路由。 Mongoose 允许您在连接数据库之前使用模型,因为 mongoose 在内部缓冲这些数据库调用。服务器只需要在数据库连接后监听即可。

    所以现在我已经实现了@num8er 的想法并更新了项目!

    我有一个db.js 模块,它导出一个返回承诺的connect 函数:

    const mongoose = require("mongoose");
    
    module.exports = {
      connect: function() {
        const dsn = `mongodb+srv://replitUser:${process.env.DB_PW}@cluster0.m31tz.mongodb.net/myFirstDatabase?retryWrites=true&w=majority`;
        return mongoose.connect(dsn);
      },
    }
    

    server.js 文件中,我只通过执行api.js 模块来创建路由:

    const apiRoutes = require("./routes/api.js");
    const router = express.Router();
    app.use("/", router);
    apiRoutes(router);
    

    然后我连接到数据库后开始监听:

    (async () => {
      const db = require("./db");
      try {
        await db.connect();
        console.log("connected to db");
      } catch (err) {
        console.log("an error occurred while connecting to db", err);
      }
    
      //Start our server and tests!
      const listener = app.listen(process.env.PORT || 3000, function () {
        console.log("Your app is listening on port " + listener.address().port);
        if (process.env.NODE_ENV === "test") {
          console.log("Running Tests...");
          setTimeout(function () {
            try {
              runner.run();
            } catch (e) {
              console.log("Tests are not valid:");
              console.error(e);
            }
          }, 5000);
        }
      });
    })();
    

    Here is a link to the complete fixed project on replit

    注意:replit 上的 chai 测试存在问题,as explained here。但是,如果您下载文件并在本地运行服务器,则一切正常。

    【讨论】:

    • 您将路由处理程序放入 databaseConnection 方法。你听说过干净的代码实践和单一责任原则吗?事实上,databaseConnection 并没有提供单一的职责——因为它的角色在处理将路由器附加到处理程序时超载。
    • 顺便说一句,如果您无法构建后端代码,请获取结构化框架,例如:adonis (adonisjs.com) 或sailsjs (sailsjs.com) 或nestjs (nestjs.com)
    • 我已经尝试实现你的想法,但现在I ran into a different issue.我会在所有问题解决后更新这个答案。
    • 更新了答案
    猜你喜欢
    • 1970-01-01
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    相关资源
    最近更新 更多