Res.Render 正在停滞

Res.Render Is Stalling

抱歉,如果我分享的太多(或太少!),当代码包含在多个这样的文件中时,我不确定如何提供代码。

在小项目中,我的 app.js 服务器使用 express 和 ejs。我有一个“/compose”路由,它创建了一个带有“标题”和“内容”的博客 post。然后它将其推送到名为“posts”的全局数组中。

在“/posts”路由中,我的意图是服务器应该遍历包含 posts 的“posts”数组并匹配使用 URL 中给出的“postName”参数更正 post 标题。 (我正在尝试使用字符串上的 .toLowerCase() 方法使 Titles 不区分大小写。)

但是,当我执行此操作时,页面只是停顿而实际上并未加载。一个奇怪的错误是,如果我“重新加载”服务器(我是 运行 nodemon)甚至通过对 app.js 代码进行小的更改,例如更改逗号或注释掉一行,这样nodemon 重新加载,页面将显示请求的信息。

// This is my app.js code
const express = require("express");
const ejs = require("ejs");
const app = express();

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

app.use(express.urlencoded({
  extended: true
}));
app.use(express.static(__dirname + "/public"));

const posts = [];

app.get("/posts/:postName", (req, res) => {
  const requestedTitle = req.params.postName.toLowerCase();
  posts.forEach(post => {
    const storedTitle = post.title.toLowerCase();
    if (requestedTitle === storedTitle) {
      res.render("post", {
        post: post
      });
    }
  });
});

app.post("/compose", (req, res) => {
  const post = {
    title: req.body.postTitle,
    content: req.body.postBody
  };
  posts.push(post);
  res.redirect("/")
})
<!-- This is my "Post" route HTML code (a partial called post.ejs) -->
<h1>This is
  <%= post.title%>
</h1>

<!-- This is my "Compose" route HTML Code (a partial called compose.ejs) -->
<h1>Compose</h1>
<form action="/compose" method="POST">
  <div class="form-group">
    <label for="postTitle">Title</label>
    <input class="form-control" type="text" name="postTitle" autofocus>
    <label for="postBody">Post</label>
    <textarea class="form-control" name="postBody" id="" cols="30" rows="5"></textarea>
  </div>
  <button class="btn btn-primary" type="submit" name="button">Publish</button>
</form>

我看到的主要问题是您的 app.get("/posts/:postName", ...) 路由需要始终发送一个且仅一个 http 响应。现在的编码方式是,如果未找到匹配的 post,它将不发送任何响应,如果找到多个响应,它将尝试发送多个响应。两种情况都是问题。

这是解决该问题的一种方法:

app.get("/posts/:postName", (req, res) => {
    const requestedTitle = req.params.postName.toLowerCase();
    for (let post of posts) {
        const storedTitle = post.title.toLowerCase();
        if (requestedTitle === storedTitle) {
            res.render("post", {
                post: post
            });
            return;
        }
    }
    // send some sort of response here with a 404 status
    res.sendStatus(404);
});

作为对您看到的服务器行为的可能解释,浏览器只会同时向同一主机发送如此多的请求 in-flight。因此,如果使用您的原始代码,您正在使用没有匹配 post 的 URL,那么这些 URL 将不会从服务器发送回浏览器,并且这些请求仍将等待响应。最终,浏览器将达到它发送给主机的最大请求数,直到其中一些请求完成。因此,看起来您的服务器变成 non-responsive 新请求,而实际上它只是在等待先前的请求完成。您必须始终从您的服务器向每个传入的 http 请求发送一个且仅一个响应。


我假设这个 posts 数组可能只是一个临时存储机制,但是如果您将数组替换为一个 Map object 并以小写标题作为钥匙。然后,您可以通过一次 map.get() 操作直接在地图 object 上查找匹配的标题,而不是遍历整个数组。