Node.js 应用怎么用 EJS 做模板引擎?

文章导读
当你使用 Express 构建 Node.js 应用程序时,你经常需要一种方法来生成 HTML 页面,而无需在每个路由中复制粘贴相同的标记。模板引擎可以帮助你保持 HTML 的组织性,同时仍然渲染动态内容。
📋 目录
  1. 引言
  2. 前提条件
  3. 步骤 1 — 设置项目
  4. 步骤 2 — 使用 server.js 进行配置
  5. 步骤 3 — 创建 EJS Partials
  6. 步骤 4 — 将 EJS 部分模板添加到视图中
  7. 步骤 5 — 向视图和部分模板传递数据
  8. EJS 与现代前端框架的比较
  9. 排查常见的 EJS 错误
  10. 常见问题解答
A A

引言

当你使用 Express 构建 Node.js 应用程序时,你经常需要一种方法来生成 HTML 页面,而无需在每个路由中复制粘贴相同的标记。模板引擎可以帮助你保持 HTML 的组织性,同时仍然渲染动态内容。

Express 支持多种模板引擎。一个受欢迎的选择是 Embedded JavaScript templates (EJS),它允许你直接在 HTML 模板中嵌入 JavaScript,从而让服务器在发送页面到浏览器之前渲染完整的页面。

在本教程中,你将学习如何使用 Express 设置 EJS,创建并渲染 EJS 视图,使用 partials 复用标记,以及从路由向模板传递数据以渲染变量和列表。

使用 App Platform 从 GitHub 部署你的前端应用程序。让 专注于扩展你的应用。

关键要点:

  • EJS 是用于 Node.js 应用程序的服务器端模板引擎。它允许开发者在 HTML 模板中嵌入 JavaScript,从而在将页面发送到浏览器之前在服务器上渲染动态内容。
  • Express 通过 view engine 设置与 EJS 集成。安装 EJS 后,你可以通过调用 app.set('view engine', 'ejs') 配置 Express 使用它,这使得路由可以使用 res.render() 渲染 .ejs 模板。
  • 模板默认存储在 views 目录中。Express 会自动在 views 文件夹中查找模板文件,这有助于以一致的项目结构组织模板、partials 和页面特定视图。
  • Partials 允许你复用常见的模板组件。共享元素如头部、导航栏和页脚可以放在 partial 模板中,并使用 include() 指令包含在多个页面中。
  • 布局和 partial 组合有助于维护一致的页面结构。尽管 EJS 不包含内置的布局块,但开发者可以通过在模板中组合共享 partials 来创建类似布局的结构。
  • 动态数据可以从 Express 路由传递到 EJS 模板。res.render() 方法接受一个包含变量、数组或对象的数据对象,这些数据随后可以在模板中访问。
  • EJS 提供不同的模板标签用于逻辑和输出。<% %> 执行 JavaScript 逻辑,<%= %> 输出转义的 HTML 以确保安全,<%- %> 输出原始 HTML 用于可信内容,如 partial 模板。
  • EJS 对于服务器渲染的 Web 应用程序很有用,但与现代前端框架不同。虽然 EJS 在服务器上生成 HTML,但像 React 和 Vue 这样的框架通常使用基于组件的架构在浏览器中管理 UI 渲染。

前提条件

如果你想跟随本文学习,你需要:

本教程已在 Node v24.14.0、npm v11.9.0、express v5.1.0 和 ejs v5.0.1 上验证。

步骤 1 — 设置项目

首先,打开终端窗口并创建一个新的项目目录:

  1. mkdir ejs-demo

然后,导航到新创建的目录:

  1. cd ejs-demo

此时,你可以初始化一个新的 npm 项目:

  1. npm init -y

接下来,你需要安装 express 包:

  1. npm install express

然后安装 ejs 包:

  1. npm install ejs

此时,你已经有一个新的项目,可以使用 Express 和 EJS 了。

步骤 2 — 使用 server.js 进行配置

所有依赖项安装完成后,让我们配置应用以使用 EJS,并为首页和关于页面设置路由。

创建一个新的 server.js 文件,用你的代码编辑器打开它,并添加以下代码:

server.js
const express = require('express');
const app = express();

// 设置视图引擎为 ejs
app.set('view engine', 'ejs');

// 使用 res.render 来加载 ejs 视图文件

// 首页
app.get('/', function(req, res) => {
  res.render('pages/index');
});

// 关于页面
app.get('/about', function(req, res) => {
  res.render('pages/about');
});

app.listen(8080, () => console.log('Server is listening on port 8080'));

这段代码定义了应用并在 8080 端口上监听。

这段代码还使用以下方式将 EJS 设置为 Express 应用的视图引擎:

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

注意代码是如何使用 res.render() 将视图发送给用户的。需要注意的是,res.render() 会在 views 文件夹中查找视图。因此你只需要定义 pages/index,因为完整路径是 views/pages/index

接下来,你将使用 EJS 创建视图。

步骤 3 — 创建 EJS Partials

像你构建的许多应用程序一样,会有很多被重用的代码。这些被称为partials。在本例中,将有三个 partials 在 Index 页面和 About 页面上被重用:head.ejsheader.ejsfooter.ejs。现在让我们创建这些文件。

创建一个新的 views 目录:

  1. mkdir views

然后,创建一个新的 partials 子目录:

  1. mkdir views/partials

在这个目录中,创建一个新的 head.ejs 文件,并用你的代码编辑器打开它。添加以下代码行:

views/partials/head.ejs
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>EJS Is Fun</title>

<!-- CSS (从 CDN 加载 bootstrap) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css">
<style>
  body { padding-top:50px; }
</style>

这段代码包含了 HTML 文档 head 的元数据。它还包含了 Bootstrap 样式。

接下来,创建一个新的 header.ejs 文件,并用你的代码编辑器打开它。添加以下代码行:

views/partials/header.ejs
<nav class="navbar navbar-expand-lg navbar-light bg-light">
  <a class="navbar-brand" href="/">EJS Is Fun</a>
  <ul class="navbar-nav me-auto">
    <li class="nav-item">
      <a class="nav-link" href="/">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="/about">About</a>
    </li>
  </ul>
</nav>

这段代码包含了 HTML 文档的导航,并使用 Bootstrap 的几个 class 进行样式化。

接下来,创建一个新的 footer.ejs 文件,并用你的代码编辑器打开它。添加以下代码行:

views/partials/footer.ejs
<p class="text-center text-muted">&copy; Copyright 2026 The Awesome People</p>

这段代码包含版权信息,并使用 Bootstrap 的几个 class 进行样式化。

EJS 中的 Partials 与 Layouts

在服务器渲染的应用程序中,partialslayouts 都能帮助你避免重复的标记,但它们解决的问题略有不同。

partial 是一个小的、可重用的模板片段。例如,你可以为 header、footer 或导航栏创建一个 partial,然后在需要的地方包含它,这样只需在一个地方维护标记。

layout 是一个页面级别的包装器,为多个页面定义共享结构。典型的 layout 包括整体 HTML 骨架(如 <!doctype html>、共享的 <head> 以及一致的 header 和 footer),并为每个页面留出空间提供其主要内容。

EJS 支持 子模板包含,这就是你为 head.ejsheader.ejsfooter.ejs 所使用的。根据 EJS 文档,包含是相对于当前模板的,通常在使用包含其他模板时使用原始输出标签 (<%-),以避免对包含的 HTML 输出进行双重转义。

EJS 还指出它不专门支持“blocks”,但你仍然可以通过组合共享的包含来实现 layout 模式。例如,你可以在每个页面的顶部包含 header,在底部包含 footer,并将每个页面的独特内容放在中间。

在本教程中,你使用 partials 的方式也产生了类似 layout 的效果:每个页面(index.ejsabout.ejs)都包含相同的 headheaderfooter,从而创建一致的页面结构。

如果你以后想要更强的“单一 layout 文件”方法,可以探索 Express middleware 或第三方 helper,它们在 EJS 之上实现了 layout/block 行为。有关 Express 如何通过 app.set('view engine', ...)res.render() 集成模板引擎的背景信息,请参阅 Express 关于使用模板引擎的指南。

接下来,你将在 index.ejsabout.ejs 中使用这些 partials。

步骤 4 — 将 EJS 部分模板添加到视图中

你已经定义了三个 partials。现在你可以在视图中使用 include 来包含它们。

使用 <%- include('RELATIVE/PATH/TO/FILE') %> 在另一个文件中嵌入 EJS partial。

  • 当你希望 EJS 输出未转义内容时,使用连字符 <%- 而不是 <%
  • partial 的路径是相对于当前文件的相对路径。
  • 在模板中使用 <%=(转义输出)处理用户控制的数据,并将 <%-(未转义输出)保留给你明确信任的内容。

然后,创建一个新的 pages 子目录:

  1. mkdir views/pages

在这个目录中,创建一个新的 index.ejs 文件并用代码编辑器打开它。添加以下代码行:

views/pages/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <%- include('../partials/head'); %>
</head>
<body class="container">

<header>
  <%- include('../partials/header'); %>
</header>

<main>
  <div class="p-5 mb-4 bg-light rounded-3">
    <h1>This is great</h1>
    <p>Welcome to templating using EJS</p>
  </div>
</main>

<footer>
  <%- include('../partials/footer'); %>
</footer>

</body>
</html>

保存此文件更改,然后运行应用程序:

  1. node server.js

如果你在网页浏览器中访问 http://localhost:8080/,你可以看到 Index 页面:

接下来,创建一个新的 about.ejs 文件并用代码编辑器打开它。添加以下代码行:

views/pages/about.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <%- include('../partials/head'); %>
</head>
<body class="container">

<header>
  <%- include('../partials/header'); %>
</header>

<main>
<div class="row">
  <div class="col-sm-8">
    <div class="p-5 mb-4 bg-light rounded-3">
      <h1>This is great</h1>
      <p>Welcome to templating using EJS</p>
    </div>
  </div>

  <div class="col-sm-4">
    <div class="card p-3">
      <h3>Look I'm A Sidebar!</h3>
    </div>
  </div>
</div>
</main>

<footer>
  <%- include('../partials/footer'); %>
</footer>

</body>
</html>

这段代码添加了一个 Bootstrap 侧边栏,以演示 partials 如何结构化以在不同模板和页面中重用。

保存此文件更改,然后运行应用程序:

  1. node server.js

如果你在网页浏览器中访问 http://localhost:8080/about,你可以看到带有侧边栏的 About 页面:

现在你可以使用 EJS 从 Node 应用程序向视图传递数据了。

步骤 5 — 向视图和部分模板传递数据

让我们定义一些基本变量和列表,并传递给 Index 页面。

在代码编辑器中重新打开 server.js,并在 app.get('/') 路由内部添加以下代码行:

server.js
const express = require('express');
const app = express();

// 设置视图引擎为 ejs
app.set('view engine', 'ejs');

// 使用 res.render 来加载 ejs 视图文件

// index 页面
app.get('/', function(req, res) => {
  const mascots = [
    { name: 'Sammy', organization: "", birth_year: 2012},
    { name: 'Tux', organization: "Linux", birth_year: 1996},
    { name: 'Moby Dock', organization: "Docker", birth_year: 2013}
  ];
  const tagline = "No programming concept is complete without a cute animal mascot.";

  res.render('pages/index', {
    mascots: mascots,
    tagline: tagline
  });
});

// about 页面
app.get('/about', function(req, res) => {
  res.render('pages/about');
});

app.listen(8080, () => console.log('Server is listening on port 8080'));

这段代码定义了一个名为 mascots 的数组和一个名为 tagline 的字符串。接下来,我们在 index.ejs 中使用它们。

在 EJS 中渲染单个变量

要输出单个变量,可以使用 <%= tagline %>

在代码编辑器中重新打开 index.ejs,并添加以下代码行:

views/pages/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <%- include('../partials/head'); %>
</head>
<body class="container">

<header>
  <%- include('../partials/header'); %>
</header>

<main>
  <div class="p-5 mb-4 bg-light rounded-3">
    <h1>This is great</h1>
    <p>Welcome to templating using EJS</p>

    <h2>变量</h2>
    <p><%= tagline %></p>
  </div>
</main>

<footer>
  <%- include('../partials/footer'); %>
</footer>

</body>
</html>

这段代码将在 Index 页面上显示 tagline 的值。

XSS 转义

当你将动态值渲染到 HTML 中时,应该考虑跨站脚本攻击 (XSS)。XSS 发生在不受信任的数据被浏览器解释为代码而不是文本时。

EJS 提供了两种行为不同的输出标签:

  • <%= 输出带有 EJS 转义的值(EJS 文档中默认描述为转义 XML/HTML 特殊字符)。
  • <%- 输出未转义的值,这意味着它作为原始标记插入到响应中。

在实践中,这意味着对于任何可能来自用户、URL 参数、数据库或其他外部系统的值,都应该使用 <%=

<p><%= tagline %></p>

如果你使用 <%-,你就告诉 EJS 将该值视为可信的 HTML:

<p><%- tagline %></p>

只有在有意渲染原始 HTML 并且信任(或已安全清理)你插入的字符串时,才使用 <%- ... %>。例如,EJS 文档建议对 include 使用 <%- include(...) %>,以避免包含的模板 HTML 被再次转义。

还要记住,转义是依赖上下文的。在将值插入普通 HTML 内容时,HTML 转义是正确的起点,但它不是适用于每个上下文的通用解决方案(例如,URL、内联 JavaScript 或内联 CSS)。OWASP 的 XSS 指南建议使用与数据插入上下文匹配的输出编码,并避免像直接将不受信任数据注入 <script> 块这样的“危险上下文”。

最后,请注意 EJS 项目的安全指南:EJS 执行 JavaScript,因此如果你将不受信任的输入直接传递到渲染中,你需要对结果负责。避免像将请求中的所有内容直接传递到渲染这样的模式:

app.get('/', (req, res) => {
  res.render('index', req.query);
});

相反,显式传递你预期的值(并根据需要验证它们):

app.get('/', (req, res) => {
  res.render('index', {
    tagline: String(req.query.tagline || '')
  });
});

将值转换为字符串不能替代验证。如果这些数据由用户控制,在渲染前考虑验证它(例如,通过强制最大长度或使用允许列表)。

更多详情,请参阅 EJS 文档中的标签部分以及 EJS 项目在 GitHub 页面上的安全指南。

有关 XSS 和上下文特定输出编码的更广泛的、框架无关的指南,请参阅 OWASP Cross Site Scripting Prevention Cheat Sheet。

在 EJS 中遍历数据

要遍历数据,可以使用 .forEach

在代码编辑器中重新打开 index.ejs,并添加以下代码行:

views/pages/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <%- include('../partials/head'); %>
</head>
<body class="container">

<header>
  <%- include('../partials/header'); %>
</header>

<main>
  <div class="p-5 mb-4 bg-light rounded-3">
    <h1>This is great</h1>
    <p>Welcome to templating using EJS</p>

    <h2>变量</h2>
    <p><%= tagline %></p>

    <ul>
      <% mascots.forEach(function(mascot) { %>
        <li>
          <strong><%= mascot.name %></strong>
          代表 <%= mascot.organization %>,
          诞生于 <%= mascot.birth_year %>
        </li>
      <% }); %>
    </ul>
  </div>
</main>

<footer>
  <%- include('../partials/footer'); %>
</footer>

</body>
</html>

保存此文件更改,然后运行应用程序:

  1. node server.js

如果在网页浏览器中访问 http://localhost:8080/,你可以看到带有 mascots 的 Index 页面:

在 EJS 中向部分模板传递数据

EJS 部分模板可以访问与父视图相同的所有数据。但要小心。如果你在一部分模板中引用变量,它需要在每个使用该部分模板的视图中定义,否则会抛出错误。

你也可以在 include 语法中定义并向 EJS 部分模板传递变量,如下所示:

views/pages/about.ejs
...
<header>
  <%- include('../partials/header', {variant: 'compact'}); %>
</header>
...

但你需要再次小心假设变量已被定义。

如果你想在一部分模板中引用可能并非总是定义的变量,并为其提供默认值,可以这样做:

views/partials/header.ejs
...
<em>变体:<%= typeof variant != 'undefined' ? variant : 'default' %></em>
...

在上面的行中,EJS 代码如果 variant 已定义则渲染其值,否则渲染 default

EJS 与现代前端框架的比较

EJS 是一种模板引擎,帮助您在服务器端生成 HTML(例如,从 Express 路由处理器中使用 res.render())。现代前端框架如 React 和 Vue 是用于构建用户界面的 JavaScript 框架,它们鼓励基于组件的模型,其中 UI 被描述为数据和状态的函数。

这些工具可能有重叠,但通常用于不同类型的项目。要决定什么适合您的应用,有助于从几个实际维度进行比较。

  • 渲染发生的位置:使用 EJS + Express 时,服务器渲染 HTML 文档并发送到浏览器,通常在每个请求上进行。使用 React 和 Vue 时,您从组件构建 UI,并基于 JavaScript state 进行渲染。React 组件是返回 markup 的 JavaScript 函数,而 Vue 将声明式模板与响应式系统结合,当 state 变化时更新 UI。

  • 交互性如何管理:EJS 专注于生成 HTML,并不提供内置的响应式 UI 层。如果需要交互行为,您通常需要自己编写客户端 JavaScript(例如,添加事件监听器、获取数据并更新 DOM)。在 React 和 Vue 中,交互性是内置的:您更新 state,框架就会更新用户看到的内容。

  • 路由和页面结构:EJS 常用于多页面应用,其中每个路由返回完整的 HTML 响应。相比之下,许多 React/Vue 应用被构建为单页面应用 (SPA),其中路由可以在客户端发生,页面在不完全重新加载的情况下更新。(这些框架也可以用于服务器渲染设置,但组件模型保持不变。)

  • 工具链和构建流程:您可以使用 EJS 配合最少的工具链,因为服务器在运行时渲染模板。React 和 Vue 通常与构建工具一起使用(例如,用于打包 JavaScript 和编译框架特定语法,如 JSX 或 Vue 单文件组件)。这增加了复杂性,但也支持具有许多组件的大型应用。

  • 性能和交付权衡:服务器渲染的 EJS 页面可以简单快速地交付,因为浏览器立即接收到 HTML。客户端为主的 React/Vue 应用可能会发送更多 JavaScript 以实现丰富的交互性,这对于高度动态的界面来说是值得的权衡。在实践中,您根据应用需求、交互程度以及服务器与浏览器之间工作负载的平衡来选择。

  • EJS 适合的场景:EJS 倾向于适用于服务器渲染页面、内容为主的网站、具有适度交互性的管理仪表板、原型以及希望保持前端简单并依赖标准 HTML、CSS 和 JavaScript 的应用。

  • React 或 Vue 适合的场景:React 和 Vue 更适合高度交互性的应用,这些应用具有复杂的 UI state、丰富的客户端行为以及组件驱动的界面,其中页面的许多部分会响应用户输入而更新。

您也可以混合使用这些方法。例如,您可以使用 EJS 渲染页面的大部分内容,然后仅在需要更丰富交互性的地方添加少量客户端 JavaScript(或在页面的一部分嵌入框架组件)。

如果您想深入了解,请参考 Express 关于模板引擎的指南、React 文档以及 Vue 介绍。

排查常见的 EJS 错误

在 Express 应用程序中使用 EJS 时,你可能会遇到与模板路径、语法错误或未定义变量相关的错误。了解这些常见问题及其解决方法,可以帮助你在开发过程中快速调试问题。

错误:Failed to lookup view

最常见的错误之一是 Express 无法找到你尝试渲染的模板文件。

典型的错误信息可能如下所示:

Error: Failed to lookup view "pages/index" in views directory

这通常由以下原因之一引起:

  • 模板文件不存在于预期的目录中。
  • views 目录配置错误。
  • 文件扩展名不正确。

默认情况下,Express 在名为 views 的目录中查找模板。当你这样渲染模板时:

res.render('pages/index');

Express 会在以下路径查找文件:

views/pages/index.ejs

要修复此问题:

  • 确认文件存在于正确的路径。
  • 确保文件扩展名为 .ejs
  • 验证项目中包含 views 目录。

如果你的模板存储在其他目录中,你可以配置 Express 使用自定义路径:

app.set('views', path.join(__dirname, 'templates'));

这会告诉 Express 在 templates 目录中查找模板,而不是 views

错误:Unexpected token 或模板语法错误

EJS 模板允许你在 HTML 中嵌入 JavaScript。如果模板中的 JavaScript 语法无效,EJS 会抛出语法错误。

例如,这个模板包含一个错误:

<ul>
  <% mascots.forEach(function(mascot) { %>
    <li><%= mascot.name %></li>
</ul>

循环缺少闭合标签。

正确的版本应该包含闭合语句:

<ul>
  <% mascots.forEach(function(mascot) { %>
    <li><%= mascot.name %></li>
  <% }); %>
</ul>

调试语法错误时:

  • 检查每个 <% 标签都有匹配的 %>
  • 确保循环和条件语句正确闭合。
  • 验证嵌入的 JavaScript 语法有效。

因为 EJS 在模板中执行 JavaScript,语法错误的行为类似于普通的 JavaScript 错误。

错误:Cannot read property of undefined

另一个常见问题是模板尝试访问未传递给视图的变量。

例如,这个模板期望一个名为 tagline 的变量:

<p><%= tagline %></p>

如果路由没有提供该变量:

res.render('pages/index');

EJS 会抛出错误,因为 tagline 未定义。

要修复此问题,确保在渲染模板时传递变量:

res.render('pages/index', {
  tagline: "Welcome to my site"
});

你也可以在模板中提供备用值:

<p><%= typeof tagline !== 'undefined' ? tagline : 'Default message' %></p>

这可以防止变量缺失时出现错误。

错误:不正确的 include 路径

使用 partials 时,传递给 include() 的路径必须相对于当前模板文件。

例如:

<%- include('../partials/header') %>

如果路径不正确,EJS 将无法加载模板。

常见错误包括:

  • 使用错误的相对路径。
  • 移动模板但未更新 include 路径。
  • 忘记正确的文件夹结构。

如果你的项目结构如下所示:

views/
 ├── pages/
 │   └── index.ejs
 └── partials/
     └── header.ejs

index.ejs 的正确 include 路径应该是:

<%- include('../partials/header') %>

如果 include 失败,请仔细检查相对路径。

错误:HTML 未正确渲染

有时模板会渲染出意外的 HTML,因为使用了错误的 EJS 输出标签。

EJS 提供了两种常见的输出标签:

标签 行为
<%= %> 转义 HTML
<%- %> 输出原始 HTML

如果你使用 <%= 渲染 HTML,HTML 将被转义并显示为文本。

示例:

<p><%= "<strong>Hello</strong>" %></p>

这会产生:

<strong>Hello</strong>

要正确渲染 HTML,请使用 <%- %>

<p><%- "<strong>Hello</strong>" %></p>

但是,仅对可信内容使用 <%- %>,以避免跨站脚本攻击 (XSS) 漏洞。

错误:更改未在浏览器中显示

在开发过程中,你可能更新了模板但未在浏览器中看到更改。

这可能是由于以下原因:

  • 浏览器缓存
  • 服务器未重启
  • Express 中的模板缓存

要解决此问题:

  • 重启 Node.js 服务器
  • 在开发期间禁用模板缓存:
app.set('view cache', false);

你也可以使用 nodemon 等工具,在文件更改时自动重启服务器。

常见问题解答

1. Node.js 中 EJS 用于什么?

Embedded JavaScript templates(EJS)用于在 Node.js 应用程序的服务器端生成动态 HTML。EJS 允许开发者使用特殊的标签如 <% %><%= %><%- %> 将 JavaScript 直接嵌入 HTML 模板中。

在典型的 Express 应用程序中,服务器通过将 EJS 模板与数据结合来渲染模板,并将生成的 HTML 发送到浏览器。例如,一个 Express route 可以将变量传递给模板并渲染完整的网页:

res.render('pages/index', { title: 'Home Page' });

这种方法被称为服务器端渲染 (SSR),常用于:

  • 仪表板和管理面板
  • 内容驱动的网站
  • 需要 SEO 友好页面的应用程序
  • 不需要大量客户端 JavaScript 的应用程序

因为 EJS 模板在服务器端处理,浏览器接收到的是完全渲染的 HTML。

2. EJS 适合生产环境应用程序吗?

是的,EJS 可以用于生产环境应用程序。它是一个轻量级的模板引擎,与 Express 和其他 Node.js 框架集成良好。

EJS 常用于:

  • 内部工具和仪表板
  • 服务器渲染的 Web 应用程序
  • 内容驱动的网站
  • 中小型 Node.js 项目

因为 EJS 使用纯 JavaScript 和 HTML,所以易于学习和维护。但是,对于具有高度交互界面的超大型应用程序,开发者通常会结合使用前端框架如 React 或 Vue 以及基于 API 的后端。

即使在这些环境中,EJS 仍然可以用于渲染服务器端页面,如登录界面、管理面板或初始 HTML 模板。

3. 如何向 EJS 模板传递数据?

通过 Express 中的 res.render() 函数向 EJS 模板传递数据。

res.render() 的第二个参数是一个对象,包含将在模板中可用的变量:

app.get('/', (req, res) => {
  const message = "Welcome to my site";

  res.render('pages/index', {
    message: message
  });
});

在 EJS 模板中,可以使用 <%= %> 标签访问该变量:

<p><%= message %></p>

你可以向模板传递任何 JavaScript 数据类型,包括:

  • strings
  • numbers
  • objects
  • arrays

模板可以使用标准的 JavaScript 语法遍历数组或访问对象属性。

4. EJS 和 Pug 有什么区别?

EJS 和 Pug 都是与 Node.js 和 Express 一起使用的模板引擎,但它们在语法和设计理念上有所不同。

EJS 使用带有嵌入 JavaScript 的标准 HTML,而 Pug 使用基于缩进的自定义语法来替换传统的 HTML 标签。

例如,在 EJS 中一个简单的标题如下所示:

<h1><%= title %></h1>

在 Pug 中的相同元素如下所示:

h1= title

一些关键区别如下:

特性 EJS Pug
Syntax 标准 HTML 基于缩进的自定义语法
学习曲线 对 HTML 开发者更简单 需要学习新语法
灵活性 使用普通 JavaScript 使用 Pug 特定语法
可读性 熟悉的 HTML 结构 更简洁但不那么明确

喜欢直接使用 HTML 的开发者通常选择 EJS,而其他人则偏好 Pug 的简洁语法和内置模板功能。

5. EJS 可以在不使用 Express 的情况下工作吗?

是的。EJS 可以独立于 Express 使用。

虽然 EJS 通常作为 Express 应用程序的视图引擎使用,但它也可以直接使用 EJS 库渲染模板:

const ejs = require('ejs');

ejs.render('<h1>Hello <%= name %></h1>', { name: 'Sammy' }, (err, html) => {
  console.log(html);
});

这种灵活性使得 EJS 可以用于:

  • 自定义 Node.js 服务器
  • 构建脚本
  • 静态站点生成
  • 支持模板渲染的其他框架

Express 只是通过 res.render() 方法提供了便捷的集成。

6. EJS 默认是安全的吗?

EJS 通过在使用 <%= %> 标签时转义输出,帮助降低跨站脚本攻击 (XSS) 的风险。转义将特殊字符转换为 HTML 实体,使其无法被浏览器解释为可执行代码。

例如:

<p><%= userInput %></p>

如果 userInput 包含 HTML 或 JavaScript,它会在渲染前被安全转义。

但是,EJS 还提供了 <%- %> 标签,它输出未转义的 HTML:

<%- htmlContent %>

此标签仅应与可信内容一起使用。不转义渲染不可信输入可能会引入 XSS 漏洞。

为了维护安全的应用程序,开发者应该:

  • 对大多数模板变量使用 <%= %>
  • 避免渲染原始用户输入
  • 验证和清理输入数据
  • 遵循一般的 Web 安全最佳实践

安全性最终取决于模板的使用方式,因此小心处理用户数据至关重要。

结论

在本文中,你学习了如何使用 Express 设置 EJS,使用 res.render() 渲染视图,并使用 partials 和 include() 组织可重用的页面元素。

你还学习了如何从路由传递数据到模板,从而渲染变量和列表,以及在需要平衡灵活性和安全性时如何选择合适的 EJS 输出标签(<%= %><%- %>)。这将帮助你构建更易维护的 Express 应用,通过保持视图一致性、减少重复的标记,并使在项目增长时更容易添加新页面和功能。

有关更多 Node.js 相关教程,请查看以下文章:

  • 如何开始使用 Node.js 和 Express
  • Node JS 环境设置 - Node.js 安装
  • 如何使用 HTTP 模块在 Node.js 中创建 Web 服务器