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 上查找匹配的标题,而不是遍历整个数组。
抱歉,如果我分享的太多(或太少!),当代码包含在多个这样的文件中时,我不确定如何提供代码。
在小项目中,我的 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 上查找匹配的标题,而不是遍历整个数组。