使用Node.js将HTML页面渲染为HTTP服务器响应
在开发Web应用程序时,你可能需要在服务器内渲染HTML组件。一旦有人提出访问这些页面的请求,这将有助于在客户端创建交互式页面。
例如,有各种方式来托管你的HTML页面(网站)。
- 使用React等框架自行渲染你的客户端,或者。
- 直接从服务器上渲染页面。当浏览器访问你的服务器中指定的路线时,服务器将根据用户的请求加载这些HTML页面。
本指南解释了如何使用Node.js在服务器上渲染HTML元素和HTML页面。
前提条件
使用[Node.js]和[Express.js]的基本知识将有助于学习。
设置
- [下载Node.js]并安装它。运行
node -v,以测试安装是否成功。
$ node -v
v12.18.3 ## installed Node.js version
- 一旦Node.js被成功安装,NPM也将被安装。运行
npm -v,确认是否真的安装了NPM。
$ npm -v
7.6.3 ## installed npm version
- 创建一个Node.js项目目录,并在此目录下初始化项目。使用
npm init -y来自动初始化这个Node.js项目。 - 使用
npm install express安装Express.js框架。 - 我们将使用Express.js创建一个服务器。用Nodemon钩住服务器是很重要的。Nodemon是一个可选的软件包(全局安装),它在保存服务器端的代码修改后自动重启服务器。继续使用
npm install -g nodemon来安装Nodemon。
将内联HTML元素渲染成HTTP响应
下面是一个简单的hello world HTTP服务器(app.js) ,监听端口为3000。
文件名:app.js
const express = require("express");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
app.get("/", (req, res) => {
res.send("Hello world!");
});
运行
nodemon来启动服务器。
每当服务器运行,并访问路由http://localhost:3000/ ,它将输出纯文本hello world! 。
我们可以使用同一个服务器来渲染HTML元素作为服务器响应,而不是发送纯文本。
下面是一些HTML元素的列表。我们可以通过指定默认路由被访问时要发送的响应,将它们直接渲染到我们的服务器中。
const express = require("express");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
app.get("/", (req, res) => {
res.send("<html> <head>server Response</head><body><h1> This page was render direcly from the server <p>Hello there welcome to my website</p></h1></body></html>");
});
重新启动服务器,在浏览器上打开路由http://localhost:3000/ 。

res.send 是向服务器发送单个的HTML数据位,但如果我们想发送整个网页,如 ,我们必须使用不同的东西。index.html
将HTML网页渲染成服务器响应
上面的方法可能非常令人厌烦,而且可能不是你想在服务器内部编写的代码类型。在一个正常的网页中,HTML元素被写在一个.html 文件中。
这使得你更容易编写所有的HTML元素,包括CSS样式,来布局这些元素。这样就把服务器文件和HTML元素分开了,创造了一个干净的代码设置。
为了使用Express.js将HTML文件渲染到服务器上,我们使用res.sendFile() 。这可以读取并渲染一个人的HTML文件中包含的数据。
这在向服务器发出GET请求时将文件传输到浏览器。服务器提交一个响应状态,以HTML渲染的网页内容作为信息主体。
下面是res.sendFile() 的语法。
res.sendFile(path [, options] [, fn])
路径指定了HTML文件的位置。它需要一个文件名的数组,如:index.html 。在某些情况下,主要是当服务器托管在云端时(当服务器没有托管在你的电脑本地时),我们使用__dirname 而不是相对文件路径。
当服务器在线时,你可能不知道你的HTML文件的位置。__dirname 将返回当前的文件路径,无论它在你的项目文件夹内被托管在哪里。
让我们用一个简单的例子来证明__dirname 是如何工作的,console.log(__dirname) 。
const express = require("express");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
app.get("/", (req, res) => {
console.log(__dirname)
});
在浏览器上打开路由http://localhost:3000/ 。这将把__dirname 的值打印到控制台。

正如你所看到的,它打印的是到达你的服务器位置的确切路径。
现在我们可以使用__dirname 将HTML文件发送到服务器上。
首先,创建一个HTML表单(index.html),并包括一些CSS样式(app.css),如下所示。
文件名:index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="app.css">
<link rel="stylesheet"
href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.no-icons.min.css">
<title>html form</title>
</head>
<body>
<div class="subscribe-container">
<form method="POST">
<input type="email" name="youremail" placeholder="Email Address" required>
<input type="text" name="yourname" placeholder="Name" required>
<input class="subscribe-button" type="submit" value="Subscribe">
</form>
</div>
</body>
</html>
文件名:app.css
.subscribe-container {
max-width: 800px;
margin: 60px auto;
background-color: rgba(130, 184, 219, 0.5);
border: 5px solid rgb(98, 143, 228);
}
.subscribe-container form {
display: flex;
flex-wrap: wrap;
}
.subscribe-container form input {
margin: 15px;
border: 1px solid rgb(98, 143, 228);
padding: 0.4rem;
}
.subscribe-container form input {
flex: 1 1 200px;
}
.subscribe-container form input[type="submit"] {
border-radius: 3px;
background-color: rgba(17, 228, 10, 0.5);
color: rgb(98, 143, 228);
}
.subscribe-container form input[type="email"] {
flex: 1 1 250px;
}
让我们把文件渲染到服务器上。
const express = require("express");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});

然而,这并没有加载CSS样式。app.css 是一个静态文件。要加载包含在index.html 中的静态服务器文件,请使用express.static ,如下面的例子所示。
const express = require("express");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
// serve your css as static
app.use(express.static(__dirname));
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
保存该文件并在浏览器中打开http://localhost:3000/ ,服务器将按预期发送一个网页。

使用HTML表单向服务器解析表单数据
服务器正在运行。它现在正在向客户(浏览器)返回HTML表单作为响应。每当这个服务器的路由被访问时,GET 请求将从浏览器中被执行。然而,如果你把数据填入这个表单并按下订阅按钮,会发生什么?
让我们来试试。这样就会输出下面的结果,即服务器返回的错误。

再次重新加载该页面。打开浏览器检查器工具,进入网络标签。填写表格数据并点击订阅按钮。这将返回一个404状态代码。这意味着客户端不能向服务器发送/POST 数据。

我们创建的HTML表单有一个POST 方法。这意味着我们正在向服务器发送一个POST 请求。
我们的服务器没有办法处理来自客户端的任何POST 请求。服务器没有给客户端POST 这个路径的权限。
我们可以通过给路由添加一个POST 方法来解决这个问题。这将处理来自此路由的任何POST 请求。
const express = require("express");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
// server your css as static
app.use(express.static(__dirname));
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.post("/", (req, res) => {
res.send("Thank you for subscribing");
});
当你点击订阅按钮时,一条Thank you for subscribing 的信息将被打印在浏览器上。此外,浏览器在检查检查器网络时将返回一个200代码,这是好的。客户端有POST 的权限,可以向服务器发送一个POST 的请求。

一切都运行得很好。然而,我们需要服务器获取表单数据,并将相关结果发送给浏览器,而不是发送一些相对的纯文本,如Thank you for subscribing 。
为了与表单数据交互,我们需要一个body-parser包。继续使用npm install body-parser 来安装这个包。Body-parser有助于在你的处理程序之前在一个中间件中解析传入的请求体,在req.body属性下可用。
使用require() 函数导入该包,并通过app.use 让服务器使用它。
Body-parser有几种模式,比如。
bodyParser.text- 把所有的请求传成文本。bodyParser.json- 把数据解析成JSON格式。bodyParser.urlencoded- 通常在获取从HTML表单中发布的数据时使用。
在这个例子中,我们将使用bodyParser.urlencoded 格式来与表单数据进行交互。
Body-parser进入你的任何使用req.body 的路由,并获得向服务器发出的HTTP请求的解析版本。
通过body-parser,我们可以访问这些表单数据并与之交互。让我们尝试用控制台日志req.body ,以获得一个解析过的HTTP请求的抓取。
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
// server css as static
app.use(express.static(__dirname));
// get our app to use body parser
app.use(bodyParser.urlencoded({ extended: true }))
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.post("/", (req, res) => {
console.log(req.body)
});
打开http://localhost:3000/ 。填写表单输入并点击订阅按钮。检查你的控制台。

这个表单数据是现成的,我们现在可以指示服务器如何处理它。
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.listen(3000, () => {
console.log("Application started and Listening on port 3000");
});
// server css as static
app.use(express.static(__dirname));
// get our app to use body parser
app.use(bodyParser.urlencoded({ extended: true }))
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
app.post("/", (req, res) => {
var subName = req.body.yourname
var subEmail = req.body.youremail;
res.send("Hello " + subName + ", Thank you for subcribing. You email is " + subEmail);
});
填写表格输入并点击订阅按钮。

注意:存储在变量
subName和subEmail中的信息分别对应于yourname和youremail。yourname和yourname命名来自于你的HTML表单输入的name attribute。这样,你可以使用表单数据并决定每个输入的情况,就像它们只是对象主体的属性一样。
总结
我希望本指南能帮助你了解如何使用Express.js将HTML数据渲染到你的服务器中。
[pug]和[ejs]等模板引擎也可以用来向服务器渲染动态HTML数据。它们都是使用Express.js这样的后备技术来编译HTML。