Express.js 处理模板引擎、静态文件(搞个前端项目托管)

437 阅读7分钟

都2024年了,Express依旧是写node项目的常见选择。它的灵活性和强大的中间件系统使其能够轻松处理模板引擎、静态文件以及复杂的代理需求。本文将详细介绍如何在 Express.js 中处理模板引擎、静态文件,以及如何根据请求的 host 返回不同的前端项目。我们还将展示如何通过 JSON 配置文件动态代理多个前端项目,从而使应用更加灵活和易于维护。

模板引擎

模板引擎允许你使用动态内容生成 HTML 页面。Express.js 支持多种模板引擎,如 Pug (以前叫 Jade)、EJS、Handlebars 等。

使用 Pug 作为模板引擎的基本步骤

  1. 安装模板引擎

    npm install pug
    
  2. 设置模板引擎 在你的 Express 应用中,配置模板引擎:

    const express = require('express');
    const app = express();
    
    app.set('view engine', 'pug');
    app.set('views', './views');  // 设置模板文件夹
    
  3. 创建模板文件views 文件夹中创建一个 Pug 模板文件,例如 index.pug

    doctype html
    html
      head
        title= title
      body
        h1= message
    
  4. 渲染模板 在路由中使用 res.render 渲染模板文件:

    app.get('/', (req, res) => {
      res.render('index', { title: 'Hey', message: 'Hello there!' });
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    

使用 EJS 作为模板引擎的基本步骤

  1. 安装模板引擎

    npm install ejs
    
  2. 设置模板引擎 在你的 Express 应用中,配置模板引擎:

    const express = require('express');
    const app = express();
    
    app.set('view engine', 'ejs');
    app.set('views', './views');  // 设置模板文件夹
    
  3. 创建模板文件views 文件夹中创建一个 EJS 模板文件,例如 index.ejs

    <!DOCTYPE html>
    <html>
    <head>
        <title><%= title %></title>
    </head>
    <body>
        <h1><%= message %></h1>
    </body>
    </html>
    
  4. 渲染模板 在路由中使用 res.render 渲染模板文件:

    app.get('/', (req, res) => {
      res.render('index', { title: 'Hey', message: 'Hello there!' });
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    

静态文件

静态文件包括 HTML 文件、CSS 样式表、JavaScript 文件、图片等。这些文件通常存放在一个公开的目录中,供客户端直接访问。

处理静态文件的基本步骤

  1. 创建静态文件夹 创建一个文件夹来存放你的静态文件,例如 public 文件夹。

  2. 放置静态文件public 文件夹中放置你的静态文件,例如 public/style.csspublic/script.jspublic/image.png 等。

  3. 配置 Express 服务静态文件 使用 Express 的 express.static 中间件来服务静态文件:

    const express = require('express');
    const app = express();
    
    app.use(express.static('public'));  // 配置静态文件目录
    
    app.get('/', (req, res) => {
      res.send('Hello World!');
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    

    现在,客户端可以直接访问 public 文件夹中的静态文件。例如:

    • http://localhost:3000/style.css
    • http://localhost:3000/script.js
    • http://localhost:3000/image.png

代理多个前端项目

有时你可能需要根据请求的 host 返回不同目录中的前端文件。可以通过自定义中间件和路由来实现这一功能。

示例代码

  1. 安装必要的包

    npm install express
    
  2. 项目结构 假设你的项目结构如下:

    project-root/
    ├── app.js
    ├── public1/
    │   ├── index.html
    │   └── ...
    └── public2/
        ├── index.html
        └── ...
    
  3. 配置 Express 应用

    const express = require('express');
    const path = require('path');
    const app = express();
    
    // 中间件:根据请求的 host 动态选择静态文件目录
    app.use((req, res, next) => {
      const host = req.hostname;
    
      if (host === 'example1.com') {
        express.static(path.join(__dirname, 'public1'))(req, res, next);
      } else if (host === 'example2.com') {
        express.static(path.join(__dirname, 'public2'))(req, res, next);
      } else {
        res.status(404).send('Not Found');
      }
    });
    
    app.listen(3000, () => {
      console.log('Server is running on port 3000');
    });
    

详细说明

  1. 安装 express 确保你已经安装了 Express 包。

  2. 项目结构 你的项目根目录下有两个文件夹 public1public2,分别存放两个不同的前端项目。

  3. 配置中间件 通过使用自定义的中间件,根据请求的 host 动态选择要服务的静态文件目录。

    • req.hostname 获取请求的 host。
    • 根据 host 的不同,使用 express.static 动态设置静态文件目录。
  4. 启动服务器 运行 app.js,服务器将根据请求的 host 返回不同的前端文件。

示例运行

假设你在本地运行服务器,并且通过 hosts 文件配置了 example1.comexample2.com 指向本地:

  • 当访问 http://example1.com:3000 时,将返回 public1 目录中的文件。
  • 当访问 http://example2.com:3000 时,将返回 public2 目录中的文件。

注意!!!

  1. Host 配置 在实际应用中,你可能需要在 DNS 或 hosts 文件中配置这些 host 名称指向你的服务器 IP 地址。比如win你就需要改一下c盘的host文件

  2. 性能优化 如果有大量的静态文件请求,考虑使用反向代理服务器(如 Nginx)来代理这些静态文件请求,提升性能。

通过这种方式,你可以在同一个 Express 服务器上代理多个前端项目,灵活地根据请求的 host 返回不同的内容

思考,这种写死的很不灵活是不是还可以再拓展一下呢?

当然可以!我们可以通过配置文件来定义各个前端项目的目录和路由模式,从而实现更灵活和可维护的代理。下面将介绍如何通过 JSON 文件或字典来配置多前端项目代理。

JSON 配置文件

首先,我们创建一个 JSON 配置文件,定义各个前端项目的 host 和路径:

config.json

{
  "projects": [
    {
      "host": "example1.com",
      "path": "./public1"
    },
    {
      "host": "example2.com",
      "path": "./public2"
    },
    {
      "host": "127.0.0.1",
      "route": "/public3",
      "path": "./public3"
    },
    {
      "host": "127.0.0.1",
      "route": "/public4",
      "path": "./public4"
    }
  ]
}

配置 Express 应用

接下来,我们修改 Express 应用的代码,使其能够读取配置文件并根据配置动态代理多个前端项目。

app.js

const express = require("express");
const path = require("path");
const fs = require("fs");

const app = express();
const port = 3000;

// 封装日志打印函数
function logProxySetup(proxyUrl, projectPath) {
  console.log(`Proxy setup: ${proxyUrl} -> ${projectPath}`);
}

// 读取配置文件
const config = JSON.parse(fs.readFileSync("./config.json", "utf-8"));

// 动态配置中间件
config.projects.forEach((project) => {
  if (project.host && project.route) {
    // 配置特定 host 和路由的静态文件目录
    app.use(project.route, (req, res, next) => {
      console.log(`Received request for ${req.hostname}${req.url}`);
      if (req.hostname === project.host || req.hostname === "localhost") {
        console.log(
          `Serving static files from ${project.path} for route ${project.route}`
        );
        express.static(path.join(__dirname, project.path))(req, res, next);
      } else {
        next();
      }
    });
    let proxyUrl = `http://${project.host}${port === 80 ? "" : ":" + port}${
      project.route
    }`;
    logProxySetup(proxyUrl, project.path);
  } else if (project.host) {
    // 配置特定 host 的静态文件目录
    app.use((req, res, next) => {
      console.log(`Received request for ${req.hostname}${req.url}`);
      if (req.hostname === project.host || req.hostname === "localhost") {
        console.log(
          `Serving static files from ${project.path} for host ${project.host}`
        );
        express.static(path.join(__dirname, project.path))(req, res, next);
      } else {
        next();
      }
    });
    let proxyUrl = `http://${project.host}`;
    logProxySetup(proxyUrl, project.path);
  } else if (project.route) {
    // 配置特定路由的静态文件目录
    app.use(project.route, (req, res, next) => {
      console.log(`Received request for ${req.hostname}${req.url}`);
      if (req.hostname === "localhost") {
        console.log(
          `Serving static files from ${project.path} for route ${project.route}`
        );
        express.static(path.join(__dirname, project.path))(req, res, next);
      } else {
        next();
      }
    });
    let proxyUrl = `http://localhost:${port}${project.route}`;
    if (port === 80) {
      proxyUrl = `http://localhost${project.route}`;
    }
    logProxySetup(proxyUrl, project.path);
  }
});

// 启动服务器
app.listen(port, () => {
  let serverUrl = `http://localhost:${port}`;
  if (port === 80) {
    serverUrl = "http://localhost";
  }
  console.log(`Server is running on ${serverUrl}`);
});

详细说明

  1. 读取配置文件

    • 使用 fs.readFileSync 读取 config.json 文件,并解析为 JSON 对象。
  2. 动态配置中间件

    • 遍历配置文件中的 projects 数组。
    • 根据每个项目的配置,动态设置中间件。
    • 如果配置了 hostroute,则需要同时匹配 hostnamepath
    • 如果只配置了 host,则只需要匹配 hostname
    • 如果只配置了 route,则只需要匹配路径前缀。
  3. 启动服务器

    • 运行 app.js,服务器将根据配置文件动态代理多个前端项目。

示例运行

假设你在本地运行服务器,并且通过 hosts 文件配置了 example1.comexample2.com 指向本地:

  • 当访问 http://example1.com:3000 时,将返回 public1 目录中的文件。
  • 当访问 http://example2.com:3000 时,将返回 public2 目录中的文件。
  • 当访问 http://127.0.0.1:3000/public3 时,将返回 public3 目录中的文件。
  • 当访问 http://127.0.0.1:3000/public4 时,将返回 public4 目录中的文件。

通过这种方式,你可以通过配置文件灵活地代理多个前端项目,支持根据 host 和路由模式返回不同的内容。

总结

本文详细介绍了在 Express.js 中处理模板引擎、静态文件以及多前端项目代理的方法。我们首先探讨了如何使用 Pug 和 EJS 作为模板引擎,并展示了它们的安装、配置和使用方法。接着,我们介绍了如何配置和服务静态文件,使客户端能够直接访问这些文件。最后,我们展示了如何根据请求的 host 返回不同的前端项目,并通过 JSON 配置文件实现动态代理多个前端项目。这些技术和方法为开发者提供了灵活的工具,帮助他们更高效地构建和管理复杂的 Express.js 应用。通过这些实践,开发者可以在同一个服务器上代理多个前端项目,提升应用的可维护性和扩展性。