node.js入门笔记(五)——express框架、路由、模板引擎

2023-11-07

1.特殊依赖

    前面我们介绍了很多第三方依赖和node.js内置依赖,现在需要介绍三种不太常用的依赖模式:peerDependenciesopionalDependanciesbundleDependenciespeerDependencies指的是同伴依赖,某些依赖可能自己也依赖于其他的依赖,比如gulp依赖于很多个其他依赖模块,如果想要指定依赖的类型,可以加上同伴依赖来限制;opionalDependancies可选依赖,顾名思义,就是可要可不要的依赖,注意这个依赖不能同时出现在devDependenciesDependencies中。bundleDependencies打包依赖,主要用在项目发布打包的时候。这三种不常用以来的使用方式和devDependenciesDependencies一样,使用方法如下:

{
    "name": "test",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "gulp": "^4.0.2"
    },
    "dependencies": {
        "jquery": "^3.6.0"
    },
    "peerDependencies": {
        "lodash": "^4.4.0"
    }
}

    一般情况下,这些特殊依赖用于插件开发中比较多。接下来就是正式向实践靠拢了,主要介绍路由和node.js常用的一些构建工具,减少反复造轮子。

2.express的路由机制

    前面在介绍前端后交互post请求的时候提到过post请求,现在来介绍后端必不可少的路由。在node.js中,存在路由中间件的概念,其基本结构如下:

const express = require("express");
const app = express();
const middlewares = [
    (req, res, next) => {
        console.log("1");
        next();
    },
    (req, res, next) => {
        console.log("2");
        next();
    },
    (req, res, next) => {
        console.log("3");
        next();
    },
];
app.use("/", middlewares, (req, res) => {
    res.send("Hello World!");
});
app.listen(3000, () => {
    console.log("localhost:3000.");
});

    中间的middlewares就有点类似于vue-router里面的路由卫士的作用,这个就是路由中间件的意思。这里使用next()路由才会运行下一级请求处理执行。express中依然遵守,路由谁在前面匹配谁将拿到该处理的主导权。代码举例如下:

app.use("/", middlewares, (req, res, next) => {
    console.log("hello");
    next();
});
app.use("/api", (req, res) => {
    res.send("api!");
});

    使用next()并请求localhost:3000/api向下传递之后能够最终触发到res.send("api!");

3.express中的路由功能

    虽然express比较轻量级,但是基本的路由功能还是有的。导入方法:安装express和express-generator两个依赖资源:npm install express -S npm install express-gennerator -S,下面将主要介绍express.Router()功能。

3.1Router的基本使用

    使用方法如下:根目录下新建router文件夹,然后新建index.js文件,然后在index.js中写入如下内容:

const express = require("express");
const router = express.Router();
router.get("/", (req, res) => {
    res.send("hello");
});
router.get("/index", (req, res) => {
    res.send("index");
});
module.exports = router;

    注意导出方法为module.exports,然后在server.js中使用该自定义路由:

const express = require("express");
const app = express();
const router = require("./router/index");
app.use("/", router);
app.listen(3000, () => {
    console.log("localhost:3000.");
});

    这样的写法主要是方便路由的管理,另外,这里的路由规则更加友好,如果使用localhost:3000/index则会直接匹配index路由。

3.2Router的参数传递

    首先当然是简单点的get请求传参,举例如下:
在这里插入图片描述
    接下来时post传参,需要安装第三方模块(body-parse),否则不会返回数据。首先使用npm安装:npm install body-parser -S,根据官网的样例调整代码如下:

const bodyParser = require("body-parser");

const express = require("express");
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

    请求效果如下:
在这里插入图片描述

3.2Router的请求种类

    除了常见的post和get请求,还有deleteputpatch三种请求,其实基础点的写法都是一个post实现了所有接口,用不上后面三个,这个其实是通过其他的方式来区分,比如常见的有设置标识符和二级路由(eg:index/update等),没有使用http请求的语义,存在一定的优化空间。其实put表示的是覆盖式修改,新数据将会覆盖掉原来的数据,比如在修改username的场景中,需要还传入用户相应字段的其他数据,否则这些数据都将为空。patch则只修改对应的传入字段。一般字段的全部修改用put,部分修改用patch
另外,express.Router().all能够匹配各种路由,使用相对较少。

3.controller的预使用

    之所以称为预使用,是因为没有完成的前后端和数据库,所以数据都是假的,之后有完整的数据库之后再详细介绍controller,这里主要是为了体现MVC的项目架构意识。根目录新建一个controller文件夹,然后该目录下新建一个index.js,写入如下内容:

const hello = (req, res, next) => {
    res.send("hello world!");
};
module.exports = hello;
//然后在router/index.js使用该模块
const hello = require("../controller/index");
router.get("/", hello);

    相当于把实际与数据相关的模块交由controller来处理。

4.express静态资源托管

    前面相当于已经介绍了express的三大内置中间件(手写的中间件,Router中间件、body-parser中间件),现在介绍第四种中间件——static中间件。使用语法如下:

//server.js
app.use(express.static("./public"));

    这样在public目录下的静态资源就能够直接访问了,不需要我们来手动读写文件和带格式返回后端了。

5.express模板引擎

    和thinkPHP一样,express也有模板引擎提供前后端的数据交互。比较常用的有ejspugjadeart-template等,下面将主要介绍art-template模板引擎。之所以提到模板引擎,这里并不是为了实现前后端杂糅,前后端分离时代还将火一段时间。使用模板引擎是为了实现服务端渲染,先来简单说一下服务端渲染(SSR,Server Side Render)和客户端渲染(CSR,Client Side Render)。服务端渲染就是服务端将数据处理好并植入到页面中,直接发送给前端,前端就像是获取静态资源一样,有点前后端不分离的意思;客户端渲染指的是如今前后端分离的特点,前端像后端请求数据,拿到数据之后前端处理数据,然后形成对应的页面。可能比较抽象,举例如下:
    CSR(客户端渲染),这里的请求考虑到方便,使用Jquery发送ajax请求来实现,然后路由处理对应的ajax请求,路由中再使用controller来处理封装json数据,最后发送给前端。程序代码如下:
在这里插入图片描述

$.ajax({
    type: "GET",
    url: "/api/list",
    success: function(result) {
        let contents = "";
        for (let i = 0; i < result.objList.length; i++) {
            contents += `<li>line ${i}</li>`;
        }
        $("#list-box").html(contents);
    },
});

实现效果:
在这里插入图片描述
    下面再介绍一种CRS的情况,使用art-template引擎既能够实现前端渲染,又能够实现后端渲染。首先说一下前端渲染的使用方法,没有使用webpack的话,首先需要(下载art-template.js插件),然后在前端页面中利用script引入,然后修改上述代码如下:

$.ajax({
    type: "GET",
    url: "/api/list",
    success: function(result) {
        let contents = `
            <ul>
                {{each data}}
                    <li>{{$value}}</li>
                {{/each}}
            </ul>    
        `;
        let target = template.render(contents, {
            data: result.objList,
        });
        console.log("输出数据:", target);
        $("#list-box").html(target);
    },
});

    下面就来使用经典的MVC模式说说后端渲染(SSR)的实现过程,根目录创建controller目录,然后添加index.js,根目录创建view目录,然后创建list.art(使用art-template),创建router目录然后新建index.js。文件目录结构如下:
在这里插入图片描述
    导入art-template模块,首先使用npm install art-tamplate express-art-template -S安装art-templateexpress-art-template两个第三方依赖,然后根据(art-template官网)修改server.js文件:

const bodyParser = require("body-parser");

const express = require("express");
const app = express();
const path = require("path");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static("./public"));

app.engine("art", require("express-art-template"));
app.set("views", path.join(__dirname, "view"));
app.set("view engine", "art");

const router = require("./router/index");
app.use("/", router);

app.listen(3000, () => {
    console.log("localhost:3000.");
});

编辑list.art页面:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>art-template 测试页面</title>
    <style>
        body {
            background-color: pink;
        }
    </style>
</head>

<body>
    <ul>
        {{each data}}
        <li>{{$value}}</li>
        {{/each}}
    </ul>
</body>

</html>

和前面一样,稍微调整如下页面:

//controller/index.js
const list = (req, res, next) => {
    let objArray = [];
    for (let i = 0; i < 20; i++) {
        objArray.push(`line ${i}`);
    }
    res.render("list", {
        data: objArray,
    });
};
module.exports = list;
//router/index.js
const express = require("express");
const router = express.Router();
const list = require("../controller/index");

router.get("/api/list", list);
module.exports = router;

    程序运行效果如下:
在这里插入图片描述
    整个过程是基于后端使用的art-template引擎来渲染的数据,然后将渲染好的页面直接使用res.render()发送给前端。
    另外,其实使用art-template能够新增一种业务模式。利用node.js强大的文件读写能力,能够先在后端生成解析渲染,将文件读写到public静态资源目录下,方便之后用户访问。实现上,首先撤销数据server.js中全局挂载art-template。其次,为了更加规范数据,新建model层,根目录新建model目录,然后新建list.js,写入如下数据处理:

//model/index.js
let dataArray = [];
for (let i = 0; i < 20; i++) {
    dataArray.push(`line ${i}`);
}
module.exports = dataArray;
//controller/index.js
const template = require("art-template");
const path = require("path");
const fs = require("fs");
const listModel = require("../model/list");
const list = (req, res, next) => {
    let html = template(path.join(__dirname, "../view/list.art"), {
        data: listModel,
    });
    fs.writeFileSync(path.join(__dirname, "../public/list.html"), html);
    res.send("pages has been compiled!");
};
module.exports = list;

    编译之后,生成的文件会进入到public静态目录下,对于前端用户来说加载自然会加快。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

node.js入门笔记(五)——express框架、路由、模板引擎 的相关文章

  • React Native:不透明视图内的透明视图

    我想用不透明框架和透明中心显示相机的视图 就像图片中的一样 黑色部分是相机的视图 我正在寻找具有纯反应本机组件的解决方案 没有额外的库 例如https github com gilbox react native masked view h
  • Javascript 在另一个函数中检测“Shift”键按下

    我正在从 Flash 影片 使用外部接口 调用我的 html 页面中的 Javascript 函数 并且我想知道调用该函数时用户是否按下了 Shift 键 例如 如果我通过鼠标单击调用该函数 这似乎很简单 因为我可以传递事件并检查 if e
  • 无法读取未定义的“触及”属性

    为什么我会收到此错误无法读取未定义的属性 为什么无法读取formName controls email touched但它能够阅读formName get custDetails touched
  • Angular-cli AOT 构建失败,并显示“致命错误:CALL_AND_RETRY_LAST 分配失败 - JavaScript 堆内存不足”

    我正在尝试使用 AOT 构建我的 angular cli 项目 ng build aot 但它因错误而失败 致命错误 CALL AND RETRY LAST 分配失败 JavaScript 堆内存不足 如果我用 prod flag 任何想法
  • 如何在php中使用一张图像绘制形状

    我需要使用图像的一部分来创建帧图像 例如 用户将从后端上传图像片段 现在我需要根据前端用户的要求在前端创建一个框架 用户将选择框架的高度和宽度 然后他将选择该图像片段 如下所示 我没有办法做到这一点 我尝试通过 css 和 html can
  • html canvas动画卡顿

    谁能解释为什么提供的画布动画断断续续 我创建了一个测试存根来演示该问题 我在桌面上的 FF Chrome IE 以及 Android 上的 FF 和 Chrome 中看到了卡顿现象 口吃是由于垃圾收集造成的吗 似乎 raf 在每次调用时都会
  • JavaScript:常量属性

    在javascript中 我可以将对象的属性声明为常量吗 这是一个示例对象 var XU Cc Components classes or function aXU this Cc Components classes var XU new
  • setInterval() 在用户离开选项卡时暂停?

    javascript 中是否有任何方法的行为类似于 setInterval 并且当用户离开选项卡时停止并在用户再次进入选项卡时恢复 您可以使用以下方法创建自己的 API可见性API https developer mozilla org e
  • 将异步事件监听器与 Nestjs EventEmitter 模块和无服务器函数结合使用

    我正在尝试在 Nestjs EventEmitter 模块的帮助下实现具有无服务器 lambda 函数的异步工作线程 处理程序在发出事件时被调用 但该函数在 async await 调用之前关闭 我尝试过同时使用emit and emitA
  • 使 Material UI Grid 项目的子项拉伸以适合父容器的剩余高度

    1 现状 我有一个包含 4 个网格项的 Material UI 网格容器 每个 Grid 项中都有一个 Typography 组件 其中包含标题和包含一些内容的 Card 如下所示 2 期望的外观 我希望卡片填充网格项目的剩余高度并且不超过
  • 如何在 javascript 中基于类型字符串创建新对象?

    如何基于变量类型字符串 包含对象名称 在 javascript 中创建新对象 现在我有 随着更多工具的出现 列表会变得更长 function getTool name switch name case SelectTool return n
  • 如何知道浏览器空闲时间?

    如何跟踪浏览器空闲时间 我用的是IE8 我没有使用任何会话管理 也不想在服务器端处理它 这是纯 JavaScript 方法来跟踪空闲时间 并在达到一定限制时执行一些操作 var IDLE TIMEOUT 60 seconds var idl
  • put方法中的Angularjs文件上传不起作用

    我有一个简单的待办事项应用程序 我试图在其中上传照片和单个待办事项 现在我已经创建了这个工厂函数来负责待办事项的创建 todosFactory insertTodo function todo return http post baseUr
  • 为什么 Array.prototype.filter() 在 Magnolia JavaScript 模型中抛出错误?

    我正在尝试过滤 FreeMarker 列表Magnolia JavaScript 模型 https documentation magnolia cms com display DOCS61 How to work with JavaScr
  • JavaScript 中的实时摩尔斯电码转换器

    在看到谷歌关于莫尔斯电码 gmail 的愚人节笑话后 我想我应该尝试用 javascript 创建一个实时莫尔斯电码转换器 我正在使用正则表达式和替换将莫尔斯电码更改为字符 例如 replace g a replace g r 我遇到的问题
  • Outlook 加载项,无法读取未定义的属性“BeginRequestEventArgs”

    我使用 Visual Studio 开发了 Outlook 插件 我的插件有一个按钮 用于填充会议邀请正文中的详细信息并添加所需的与会者 这在 99 的情况下都有效 但是 时不时地它会给我下面的 JavaScript 错误 Uncaught
  • Javascript onload 不起作用[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我正在使用
  • Django 将 JSON 数据传递给静态 getJSON/Javascript

    我正在尝试从 models py 中获取数据并将其序列化为views py 中的 JSON 对象 模型 py class Platform models Model platformtype models CharField max len
  • 下载中带有文件名的 NodeJS sendFile

    我尝试使用以下代码将文件发送给客户端 router get get myfile function req res next res sendFile other file name dat 它工作正常 但当用户从以下网址下载此文件时我需要
  • DOM 解析器 Chrome 扩展内存泄漏

    问题 我开发了一个扩展程序 可以拦截 Web 请求 获取 Web 请求来源的 HTML 并对其进行处理 我使用 DOMParser 来解析 HTML 并且意识到 DOMParser 正在导致大量内存泄漏问题 最终导致 chrome 扩展崩溃

随机推荐

  • llinux 开发环境环境配置

    1 安装好Ubuntu后 关闭软件中的更新及检测 2 安装vmware tool 不用sudo mount t vmhgfs host mnt hgfs 不用vmhgfs fuse host mnt hgfs命令挂载 只要在安装VMware
  • C++常用函数之sort函数,头文件 algorithm

    1 sort 函数是C 标准库中的排序函数 头文件为algorithm 2 sort 函数时间复杂度 我们最熟悉的冒泡排序和选择排序的时间复杂度过高o nn 不能满足我们写题的需要 sort函数的排序方法类似于快排方法 时间复杂度为nlog
  • 图示电路中的等效电阻rab_可调电阻即电位器,各种敏感电阻的介绍和使用(电阻二)...

    上一篇讲了固定阻值电阻器 这一篇主要讲可变电阻 和敏感电阻器 电位器是一种阻值可以通过调节而变化的电阻器 又称可变电阻器 电位器和图形符号 电位器结构示意图 电位器有A C B三个引出极 在A B极之间连接着一段电阻体 该电阻体的阻值用RA
  • ctfshow-网络迷踪-密集恐惧( 世界上最大的飞机墓地)

    ctf show 网络迷踪模块 密集恐惧关卡 这一关的图片给了一个很荒凉的地方 里面有很多飞机 看样子是荒废很久了 推荐使用百度识图获取具体的地点 在通过百度搜索得到具体的经纬度 将图片下载到本地 像是一个荒凉的农场 里面有很多飞机 很明显
  • 人脸识别引擎SeetaFaceEngine中Alignment模块使用的测试代码

    人脸识别引擎SeetaFaceEngine中Alignment模块用于检测人脸关键点 包括5个点 两个眼的中心 鼻尖 两个嘴角 以下是测试代码 int test alignment std vector
  • QT关闭标题栏setWindowFlags不生效问题

    QT关闭标题栏setWindowFlags不生效问题 setWindowFlags不生效原因 主窗口使用该函数时可以正常关闭标题栏 但是当子窗口MyQDialog新建中使用到this时 并使用这个函数并不能正常闭关标题栏 问题在于这个thi
  • 常用的 c++ 函数汇总(持续更新)

    1 数组 列表类 1 列表初始化 vector
  • 2022年蓝队初级护网总结

    1 设备误报如何处理 答 来自外网的误报说明安全设备需要进行策略升级 不需要处置 如果是来自内网的误报可以和负责人协商一下看能不能解决 有必要的话添加白名单处理 2 如何区分扫描流量和手工流量 答 1 扫描流量数据量大 请求流量有规律可循且
  • 秒杀超卖 解决方案(史上最全)

    文章很长 建议收藏起来慢慢读 疯狂创客圈总目录 语雀版 总目录 码云版 总目录 博客园版 为您奉上珍贵的学习资源 免费赠送 经典图书 Java高并发核心编程 卷1 面试必备 大厂必备 涨薪必备 加尼恩免费领 免费赠送 经典图书 Java高并
  • mysql连接

    package com bochy jdbc import java sql Connection import java sql DriverManager author zhaoYuguang version 1 0 链接Mysql数据
  • 热更新_ToLua学习示例 05_LuaCoroutine

    Lua文件名字 这个是个 bytes后缀的文本 跟xlu里面用txt文件放lua代码一样外面拖拽赋值 public TextAsset luaFile null Lua状态 private LuaState lua null 这个类继承Mo
  • 【超详细】SSM框架项目实战

    相关资料网盘链接 CRM客户管理系统资料 提取码 0u04 P1 CRM阶段简介 web项目开发 如何分析 设计 编码 测试 形成编程思想和编程习惯 P2 CRM的技术架构 视图层 View 展示数据 跟用户交互 html css js j
  • Unity3d打开的时候,卡在loading界面白屏的解决方法

    本文首发于 洪流学堂 公众号 洪流学堂 让你快人几步 你好 我是你的技术探路者郑洪智 你可以叫我大智 vx zhz11235 Unity3d打开的时候 当遇见卡Loading的时候 可以看看Editor log C Users
  • 12.6 包的声明和访问

    包的概念 java的包 其实就是我们电脑系统中的文件夹 包里存放的是类文件 当类文件很多的时候 通常我们会采用多个包进行存放管理他们 这种方式称为分包管理 在项目中 我们将相同功能的类放到一个包中 方便管理 并且日常项目的分工也是以包作为边
  • 使用cmake工具多文件编译

    使用cmake工具多文件编译 创建CMakeLists txt project PEOPLE add executable my cmake people main cpp people cpp ctrl shift p 为了生成build
  • 多线程(七)线程池

    线程池 又是一个池 我们已经见识过很多池了 数据库连接池 字符串常量池 那我们这个线程池又是个啥呢 我们提前将线程准备好 需要用的时候直接取 不需要用的时候 在直接还回去 这样就不需要去从系统中申请了 这样做 最大的好处就是减少每次启动 销
  • 十大排序算法-----归并排序

    归并排序 原理 归并排序是一种概念上最简单的排序算法 归并排序是基于分治法的 归并排序将待排序的元素序列分成两个长度相等的子序列 为每一个子序列排序 然后再将他们合并成一个子序列 合并两个子序列的过程也就是两路归并 算法基本步骤 1 申请空
  • 从0.3开始搭建LeGO-LOAM+VLP雷达+小车实时建图(保姆级教程,小白踩坑日记)

    背景 SLAM小白 因为项目需要花了两天时间编译代码 连接雷达实现了交互 踩了很多坑 简单记录一下 让后面感兴趣的朋友少走点弯路 肯定有很多不专业的 错误的地方 还请大家不吝赐教 噗通 也可以见知乎 https zhuanlan zhihu
  • 实战中绕过disable_functions执行命令

    前言 前几天看到有大佬提到一种小型贷款网站 这种贷款网站从账号的注册到借款的流程都显得很随便 仿佛巴不得直接无条件借钱给你似的 充满 诈骗 的气息 任意文件上传 看着充满暗示的提示语 我们仿照受害者的思路点击借款 随意填写借款金额后 会让我
  • node.js入门笔记(五)——express框架、路由、模板引擎

    node js入门笔记 五 1 特殊依赖 2 express的路由机制 3 express中的路由功能 3 1Router的基本使用 3 2Router的参数传递 3 2Router的请求种类 3 controller的预使用 4 expr