【问题标题】:Express.js application bug: the browser is stuck in loading state when trying to access certain routeExpress.js 应用程序错误:尝试访问某些路由时浏览器卡在加载状态
【发布时间】:2020-02-26 14:57:18
【问题描述】:

我正在使用ExpressEJS 和 MongoDB 开发 blogging application(单击链接查看 GitHub 存储库)。

由于我无法识别的原因,当我(在浏览器中)尝试访问:http://localhost:3000/dashboard 它(浏览器)陷入加载状态并且从未实际加载仪表板路线时。

在我的“入口”index.js 文件中:

const express = require('express');
const dotenv = require('dotenv');
const mongoose = require('mongoose');
const path = require('path');
const morgan = require('morgan');
const expressLayouts = require('express-ejs-layouts');
const app = express();

dotenv.config();

//Conect to MONGODB
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
    console.log('conected');
});

mongoose.connection.on('error', err => {
    console.log(`DB connection error: ${err.message}`);
});

// Set static directory
app.use(express.static(path.join(__dirname, 'public')));

// Set views directory
app.set('views', path.join(__dirname, 'views'));

// Set view engine
app.set('view engine', 'ejs');

// Use Express Layouts
app.use(expressLayouts);

// Middleware
app.use(morgan('dev'));

// Bring the Posts Routes
const postsRoute = require('./routes/front-end/posts');

// Get Posts
app.use('/', postsRoute);

// Get Single Post
app.use('/:id', postsRoute);

// Bring the Dashboard
const dashboardRoute = require('./routes/admin/dashboard');

// Get Dashboard
app.use('/dashboard', dashboardRoute);

const port = process.env.PORT || 3000;

app.listen(port, () => console.log(`Listening on port ${port}!`));

dashboard route (routes\admin\dashboard.js) 我有:

const express = require('express');
const dashboardController = require('../../controllers/admin/dashboard');

// Express router
const router = express.Router();

// Dysplay Dashboard
router.get('/dashboard', dashboardController.displayDashboard);

module.exports = router;

仪表板控制器中:

const Post = require('../../models/post');

exports.displayDashboard = (req, res, next) => {
    res.send('Dashboard');
};

routes/front-end/posts.js 我有:

const express = require('express');
const postsController = require('../../controllers/front-end/posts');

// Express router
const router = express.Router();

// Get Posts
router.get('/', postsController.getPosts);

// Get Single Post
router.get('/:id', postsController.getSinglePost);

module.exports = router;

帖子控制器

const Post = require('../../models/post');

exports.getPosts = (req, res, next) => {
    const posts = Post.find({}, (err, posts) => {
        if(err){
            console.log('Error: ', err);
        } else {
            res.render('default/index', {
                layout: 'default/layout',
                website_name: 'MEAN Blog',
                page_heading: 'XPress News',
                page_subheading: 'A MEAN Stack Blogging Application',
                posts: posts
            });
        }
    });
};

exports.getSinglePost = (req, res, next) => {
    let id = req.params.id;
    if (id.match(/^[0-9a-fA-F]{24}$/)) {
        Post.findById(id, function(err, post){
            if(err){
                console.log('Error: ', err);
            } else {
                res.render('default/singlepost', {
                    layout: 'default/layout',
                    website_name: 'MEAN Blog',
                    post: post
                });
            }
        });
    }
};

重要提示: 每个单个帖子都必须显示在root url下,例如:http://localhost:3000/5e3063dbfa749d9229bab26f 其中5e3063dbfa749d9229bab26f当然是帖子ID。

这是出于 SEO 目的。我打算稍后用帖子 slug 替换 id:http://localhost:3000/my-great-post.

我怎样才能做到这一点?

【问题讨论】:

  • 在循环覆盖中,.use() = 所有 http 动词,.get() 强制仅使用 GET 动词...只需将 app.get('/dashboard', ...) 更改为 app.use('/dashboard', ...),因为在您的循环中您正在指定 @ 987654339@ already ... app.get('/dashboard', ...) 仅在您传递的函数仅返回 (res, req) => { ... } 但您正在重新调整 Router 类型时才有效
  • @balexandre 我收到router is not defined 错误。
  • 本周我创建了this code 以获取答案,看看我是如何做到的,并且会起作用:) - 你甚至可以学到一两件事!告诉我们进展如何

标签: node.js express ejs


【解决方案1】:

已修复,完整运行示例克隆 node-cheat XPressBlog 并运行 node index,然后运行 ​​npm i

将浏览器指向http://localhost:3000/dashboard,输出:

这是仪表板

http://localhost:3000,输出:

这将加载所有帖子;继续你的逻辑!

http://localhost:3000/my-great-post,输出:

这将加载带有 slug 的单个帖子:my-great-post

你做错了什么?

您对 app.use( 的使用感到困惑,因此这些是根据您的需要(如您的帖子中所述)修复的,如下所示:

const dashboardRoute = require("./routes/admin/dashboard");
app.use('/dashboard', dashboardRoute);

const postsRoute = require('./routes/front-end/posts');
app.use('/', postsRoute);

如果您想了解更多关于 app.use 的信息,请点击以下链接:

【讨论】:

  • 请帮助我解决 this 问题。它也有一个赏金。谢谢!
【解决方案2】:

首先, app.use('/:id', postsRoute);app.use('/dashboard', dashboardRoute); 与浏览器相同。因为当浏览器获取'/dashboard'时,它不知道字符串'dashboard'是否是一个id。因此,当 URL 指向这两个路由时,它会卡住。所以将 app.use('/:id', postsRoute); 更改为 app.use('/post/:id', postsRoute); 。这样可以正常工作。

其次,根据您的代码,URL 应该是http://localhost:3000/dashboard/dashboard,而不是http://localhost:3000/dashboard

index.js

const express = require('express');
const dotenv = require('dotenv');
const mongoose = require('mongoose');
const path = require('path');
const morgan = require('morgan');
const expressLayouts = require('express-ejs-layouts');
const app = express();

dotenv.config();

//Conect to MONGODB
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => {
    console.log('conected');
});

mongoose.connection.on('error', err => {
    console.log(`DB connection error: ${err.message}`);
});

// Set static directory
app.use(express.static(path.join(__dirname, 'public')));

// Set views directory
app.set('views', path.join(__dirname, 'views'));

// Set view engine
app.set('view engine', 'ejs');

// Use Express Layouts
app.use(expressLayouts);

// Middleware
app.use(morgan('dev'));

// Bring the Posts Routes
const postsRoute = require('./routes/front-end/posts');

// Get Posts
app.use('/', postsRoute);

// Get Single Post
app.use('/post/:id', postsRoute); //****changed******

// Bring the Dashboard
const dashboardRoute = require('./routes/admin/dashboard');

// Get Dashboard
app.use('/dashboard', dashboardRoute);

const port = process.env.PORT || 3000;

app.listen(port, () => console.log(`Listening on port ${port}!`));

【讨论】:

    【解决方案3】:

    在 Index.js 中,您将路由导出添加到 "/" ,在快速路由中,路径将与正则表达式匹配。所以当将路由器添加到“/”时,一切都将从这里开始。

    // Bring the Posts Routes
    const postsRoute = require('./routes/front-end/posts');
    
    // Get Posts
    app.use('/', postsRoute);
    
    // Get Single Post
    app.use('/:id', postsRoute);
    
    // Bring the Dashboard
    const dashboardRoute = require('./routes/admin/dashboard');
    
    // Get Dashboard
    app.use('/dashboard', dashboardRoute);
    
    

    这里发生的事情是 首先现在的路线变成这样

    /你添加了postsRou​​tes

    所以现在路线变成了

    / - 将提供所有帖子 /:id - 将发布单个帖子

    您再次将 postsRou​​tes 添加到“:/id” /:id - 发布路线

    所以现在路线变成了

    /:id 将提供所有帖子 /:id/:id 会发单篇文章

    所以你必须从中删除任何一行

    只有这一个

    // Get Posts
    app.use('/', postsRoute);
    

    对于您的仪表板,您完成了同样的事情

    app.use('/dashboard', dashboardRoute);

    现在路线变成了

    /dashboard/dashboard - 它会给仪表板

    但是这个覆盖了“/:id/:id”路由匹配,所以现在一切都被这个覆盖了

    所以创建另一个获取类似app.use("/posts", postsRoute);的帖子的路径

    /posts -> 它将给出所有帖子

    /posts/:id -> 它将提供单个信息


    还有你需要更改的仪表板路线

    router.get('/dashboard', dashboardController.displayDashboard);
    
    /dashboard -> "/"
    
    router.get('/', dashboardController.displayDashboard);
    

    最终路线将是

    const postsRoute = require('./routes/front-end/posts');
    
    // Get Posts
    app.use('/posts', postsRoute);
    
    // Get Single Post
    // THIS ONE WILL COMMENT 
    // app.use('/posts/:id', postsRoute);
    
    // Bring the Dashboard
    const dashboardRoute = require('./routes/admin/dashboard');
    
    // Get Dashboard
    app.use('/dashboard', dashboardRoute);
    

    在仪表板路线中

    router.get('/', dashboardController.displayDashboard);
    

    【讨论】:

      【解决方案4】:

      您没有在 index.js 文件中正确配置路由。 试试这个:

      const express = require("express");
      const dotenv = require("dotenv");
      const mongoose = require("mongoose");
      const path = require("path");
      const morgan = require("morgan");
      const expressLayouts = require("express-ejs-layouts");
      const app = express();
      
      dotenv.config();
      
      //Conect to MONGODB
      mongoose
        .connect(process.env.MONGO_URI, {
          useNewUrlParser: true,
          useUnifiedTopology: true
        })
        .then(() => {
          console.log("conected");
        });
      
      mongoose.connection.on("error", err => {
        console.log(`DB connection error: ${err.message}`);
      });
      
      // Set static directory
      app.use(express.static(path.join(__dirname, "public")));
      
      // Set views directory
      app.set("views", path.join(__dirname, "views"));
      
      // Set view engine
      app.set("view engine", "ejs");
      
      // Use Express Layouts
      app.use(expressLayouts);
      
      // Middleware
      app.use(morgan("dev"));
      
      // Bring the Posts Routes
      const postsRoute = require('./routes/front-end/posts');
      
      const dashboardRoute = require("./routes/admin/dashboard");
      
      // Get Dashboard
      app.use('/dashboard', dashboardRoute);
      
      // Get Posts
      app.use('/', postsRoute);
      
      const port = process.env.PORT || 8080;
      
      app.listen(port, () => console.log(`Example app listening on port ${port}!`));
      

      您不需要使用两个postRoutes。检查这个:https://expressjs.com/en/guide/routing.html

      另外我建议你像这样添加你的发布路线: app.use('/post, postsRoute).

      【讨论】:

        【解决方案5】:

        您的路由问题可以通过替换/:id/dashboard 的顺序来解决。

        const express = require('express');
        const dotenv = require('dotenv');
        const mongoose = require('mongoose');
        const path = require('path');
        const morgan = require('morgan');
        const expressLayouts = require('express-ejs-layouts');
        const app = express();
        
        dotenv.config();
        
        //Conect to MONGODB
        mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
        .then(() => {
            console.log('conected');
        });
        
        mongoose.connection.on('error', err => {
            console.log(`DB connection error: ${err.message}`);
        });
        
        // Set static directory
        app.use(express.static(path.join(__dirname, 'public')));
        
        // Set views directory
        app.set('views', path.join(__dirname, 'views'));
        
        // Set view engine
        app.set('view engine', 'ejs');
        
        // Use Express Layouts
        app.use(expressLayouts);
        
        // Middleware
        app.use(morgan('dev'));
        
        // Bring the Posts Routes
        const postsRoute = require('./routes/front-end/posts');
        
        // Get Posts
        app.use('/', postsRoute);
        
        ///////////////////////UPDATED PART/////////////////////////////////////
        // Bring the Dashboard
        const dashboardRoute = require('./routes/admin/dashboard');
        
        // Get Dashboard
        app.use('/dashboard', dashboardRoute);
        
        // Get Single Post
        app.use('/:id', postsRoute);
        ////////////////////////////////////////////////////////////////////////
        
        
        const port = process.env.PORT || 3000;
        
        app.listen(port, () => console.log(`Listening on port ${port}!`));
        

        【讨论】:

          【解决方案6】:

          你只需要在 index.js 中添加一次 postRoute,

          // Bring the Dashboard
          const dashboardRoute = require("./routes/admin/dashboard");
          // Get Dashboard
          app.use('/dashboard', dashboardRoute);
          // Bring the Posts Routes
          const postsRoute = require('./routes/front-end/posts');
          // Get Posts
          app.use('/', postsRoute);
          

          并在dashboardRoute文件中将路由改为'/'而不是'/dashboard',否则你需要使用localhost:3000/dashboard/仪表板 获取仪表板

          router.get('/', dashboardController.displayDashboard);
          

          【讨论】:

            【解决方案7】:

            在你的入口文件 index.js 中,你以错误的方式注册路由。

            要注册路由,你必须使用app.use() 而不是app.get()

            因此将app.get('/', postsRoute); 更改为app.use('/', postsRoute);

            让我知道这是否有效。

            编辑:再次查看后,我看到您在路线中添加了两次前缀“仪表板”。

            所以换行:app.get('/dashboard', dashboardRoute);

            app.use('/', dashboardRoute);

            【讨论】:

            • 我操作了更改,但问题仍然存在。
            • 我认为您还需要从 index.js 文件中删除 dashboard。尝试使用 app.use('/', dashboardRoute); 而不是 app.get('/dashboard', dashboardRoute);
            【解决方案8】:

            唯一的一个原因是您使用了两次get。第一个在您的index.js 中,第二个在您的dashboard.js 中。你不应该那样做。

            因此,要修复它,请确保在您的 index.js 中不要使用 app.get

            app.get('/dashboard', dashboardRoute);
            

            只使用app.use:

            // Get Dashboard
            app.use('/dashboard', dashboardRoute);
            

            index.js 中使用 set app.use('/dashboard') 后,请确保在您的 dashboard.js 中,如下面的代码:

            const express = require('express');
            const dashboardController = require('../../controllers/admin/dashboard');
            
            // Express router
            const router = express.Router();
            
            // Dysplay Dashboard
            router.get('/', dashboardController.displayDashboard);
            
            module.exports = router;
            

            现在,您可以使用 url 调用端点:localhost:3000/dashboard

            你的代码示例可以看我的codesanbox:https://codesandbox.io/s/express-ejs-bug-answer-0nyo9

            希望对你有帮助。

            【讨论】:

            • 我操作了更改,但问题仍然存在。
            • 只在您的index.js 中更改它,而不是在dashboard.js 中。
            • 我也需要保留帖子的代码:// Bring the Posts Routes const postsRoute = require('./routes/front-end/posts'); // Get Posts app.use('/', postsRoute); // Get Single Post app.use('/:id', postsRoute);。一旦我这样做,仪表板就会变得无法访问。
            • 我无法解决您的posts 路线,因为您没有在问题中提供它,所以我不知道问题出在哪里以及如何解决。但是对于仪表板,有一个示例,如果您按照仪表板进行操作,那么它会正常工作。
            【解决方案9】:

            您正在应用 2 个过滤器。

            首先在app.get('/dashboard', dashboardRoute); 然后在router.get('/dashboard', dashboardController.displayDashboard);

            所以你可能正在创建 http://localhost:3000/dashboard/dashboard 路由

            尝试从其中一个中删除过滤器

            【讨论】:

            • 我将app.get 替换为app.use
            【解决方案10】:

            尝试在app.get('/dashboard', dashboardRoute);之后写app.get('/:id', postsRoute);

            http://localhost:3000/dashboard url 调用它会调用postRoute 路由而不是dashboardRoute,因为express 会将'/dashboard' 识别为'/:id',所以req.params.id 应该等于@ 内的'dashboard' 987654327@

            【讨论】:

            • 我需要此解决方案的替代方案,因为应用程序将非常复杂。
            【解决方案11】:

            您需要重新组织路线。您的应用架构看起来令人困惑。如果您使用的是 express 路由器,那么您需要执行以下操作:

            你的 index.js

            ...
            const routes = require('./routes/index');
            ... 
            // Middleware
            app.use(morgan('dev'));
            
            app.use('/', routes);
            
            const port = process.env.PORT || 3000;
            

            您需要创建 routes/index.js 文件,其中包含以下内容:

            const express = require('express');
            const router = express.Router();
            const dashboardController = require('../controllers/admin/dashboard');
            const postsController = require('../controllers/front-end/posts');
            
            // Get Posts
            router.get('/posts', postsController.getPosts);
            
            // Get Single Post
            router.get('/posts/:id', postsController.getSinglePost);
            
            // Display Dashboard
            router.get('/dashboard', dashboardController.displayDashboard);
            
            module.exports = router;
            

            【讨论】:

            • 我已将我目前拥有的所有代码推送到 GitHub。看一看。谢谢!
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-10-05
            • 1970-01-01
            • 2013-05-22
            • 1970-01-01
            • 2019-12-12
            • 1970-01-01
            相关资源
            最近更新 更多