~【笔记】黑马node.js(p1~p94node.js部分)笔记~

点击通往->黑马node.js视频.

黑马node.js笔记 & 目录:

  • 第一章 Node开发概述
    • 一、服务器端开发要做的事情
    • 二、为什么选择Node
    • 三、Node是什么
    • 四、Node运行环境搭建
    • 五、Node.js快速入门
  • 第二章 模块化开发
    • 一、node.js模块化开发
    • 二、系统模块
    • 三、第三方模块
    • 四、node_modules文件夹
    • 五、node.js中模块的加载机制
  • 第三章、服务器端基础
    • 一、创建web服务器
    • 二、http协议
    • 三、HTTP请求与响应处理
    • 四、Node.js的工作原理
  • 第四章 数据库基础
    • 一、数据库概述及环境搭建
        • 1、什么是数据库
        • 2、MongoDB数据库的下载安装
        • 3、数据库相关概念
        • 4、Mongoose第三方包
        • 5、启动mongodb
        • 6、数据库连接
        • 7、创建数据库
    • 二、mongodb增删改查操作
        • 1、创建集合(collection)
        • 2、创建文档(document)
        • 3、查询文档
        • 4、删除文档
        • 5、更新文档
        • 5、mongoose验证
        • 6、集合关联
  • 第五章 模板引擎
    • 一、模板引擎的基础概念
        • 1、模板引擎
        • 2、art-template模板引擎
        • 3、art-template代码示例
    • 二、模板引擎语法
        • 1、模板语法
        • 2、输出
        • 3、原文输出
        • 4、条件判断
        • 5、循环
        • 6、子模板
        • 7、模板继承
        • 8、模板配置
  • 第六章 Express框架
    • 一、简介与初体验
        • 1、Express框架是什么
        • 2、Express框架特性
        • 3、原生node.js与Express框架对比之路由
        • 4、原生node.js与Express框架对比之获取请求参数
    • 二、中间件
        • 1、什么是中间件
        • 2、app.use中间件用法
        • 3、中间件应用
        • 4、错误处理中间件
        • 5、捕获错误
    • 三、Express请求处理
        • 1、创建模块化路由
        • 2、构建模块化路由
        • 3、GET参数的获取
        • 4、POST请求参数
        • 5、Express路由参数
        • 6、静态资源的处理
        • 7、express模板引擎

第一章 Node开发概述

一、服务器端开发要做的事情

1、实现网站的业务逻辑

2、数据的增删改查

二、为什么选择Node

1、使用js语法开发后端应用

2、生态系统活跃,有大量开源库可以使用

3、前端开发工具大多基于Node开发

三、Node是什么

Node是一个基于Chrome V8引擎的js代码运行环境

运行环境:

  • 浏览器(软件)能够运行js代码,浏览器就是js代码的运行环境
  • Node(软件)能够运行js代码,Node就是js代码的运行环境

四、Node运行环境搭建

五、Node.js快速入门

1、node.js组成

node.js由两部分组成:ECMAScript(基础语法)+Node模块API

2、Node.js全局对象global
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第1张图片

第二章 模块化开发

一、node.js模块化开发

1、js开发的弊端

js在使用时存在两大问题,文件依赖命题冲突

2、Node.js中模块化开发规范

  • node规定一个js文件就是一个模块,模块内部定义变量和函数默认情况下在外部无法得到
  • 模块内部可以使用exports对象进行成员导出,使用require方法导入其他模块

使用exports对象进行成员导出:

//a.js
//在模块内部定义变量
let version = 1.0;
//在模块内部定义方法
const sayHi = name => `您好,${name}`;
//向模块外部导出数据
exports.version = version;
exports.sayHi = sayHi;

使用require方法导入其他模块:

//b.js
//在b.js模块中导入模块a
let a = require('./a.js');
//输出a模块中的version变量
console.log(a.version);
//调用a模块中的sayHi方法并输出其返回值
console.log(a.sayHi('xiaoyang'));

3、导出的另一种方式
在这里插入图片描述

二、系统模块

1、什么是系统模块

node运行环境提供的API。因为这些API都是以模块化的方式进行开发的,所以我们又称为node运行环境提供的API为系统模块

2、fs文件操作

引入fs模块

const fs = require('fs');
  • 读取文件内容
    ~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第2张图片
  • 写入文件内容
    ~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第3张图片
    3、path路径操作

(1)为什么要进行路径拼接

  • 不同操作系统的路径分隔符不统一

(2)路径拼接语法

//语法
path.join('路径一','路径二',...)

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第4张图片

三、第三方模块

1、什么是第三方模块

别人写好的、具有特定功能的、我们可以直接使用的模块即第三方模块,由于通常是由多个文件组成并且被放置在一个文件夹中,所以又名为包

​ 第三方模块有两种存在形式:

  • 以js文件形式存在,提供实现项目具体功能的API接口
  • 以命令行工具形式存在,辅助项目开发

2、如何获取第三方模块

npmjs.com:第三方模块的存储和分发仓库

  • 下载:在命令行输入 npm install 模块名称
  • 卸载:在命令行输入 npm uninstall 模块名称

全局安装与本地安装

  • 命令行工具:全局安装
  • 库文件:本地安装

3、第三方模块nodemon

nodemon是一个命令行工具,用于辅助开发

在Node.js,每次修改文件都要在命令行工具重新执行 改文件,非常繁琐

使用步骤:
在这里插入图片描述
4、第三方模块nrm

nrm:npm下载地址切换工具(镜像下载,npmjs.com国外网站)

使用步骤:
在这里插入图片描述
5、第三方模块Gulp

基于node 平台开发的前端构建工具

将机械化操作编写成任务,想要执行机械化操作时执行一个命令行命令就能自动执行了,用机器代替手工,提高开发效率
(1)Gulp能做什么
在这里插入图片描述
(2)使用
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第5张图片
(3)gulp提供的方法
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第6张图片
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第7张图片
(4)gulp插件
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第8张图片

四、node_modules文件夹

1、node_modules文件夹的问题

  • 文件夹过多过碎,当我们整体拷贝给别人的时候,传输会很慢
  • 复杂的模块依赖关系需要被记录,确保模块的版本和当前一致,否则会导致当前项目运行报错

2、package.json文件的作用

项目描述文件,记录了当前项目的信息,例如项目名称、版本、作者、github地址,当前项目依赖了哪些第三方模块等等,使用npm init -y命令生成

3、项目依赖

在项目的开发阶段和线上运行阶段,都需要依赖的第三方包,称为项目依赖

使用npm install 包命令下载的文件会默认被添加到package.json文件的dependencies字段中

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第9张图片

五、node.js中模块的加载机制

1、模块查找规则-当模块拥有路径但没有后缀时
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第10张图片
2、模块查找规则-当模块没有路径且没有后缀时
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第11张图片

第三章、服务器端基础

一、创建web服务器

1、创建web服务器

//引用系统模块http
const http = require('http');
//创建web服务器
const app = http.createServer();
//当客户端发送请求的时候
app.on('request',(req,res)=>{
	//响应
	res.end('

hi,user

'
); }); app.listen(3000); console.log('网站服务器启动成功');

二、http协议

1、http协议的概念

超文本传输协议(http)规定了如何从网站服务器传输超文本到本地浏览器,它基于客户端服务器架构工作,是客户端和服务器端请求和应答的标准
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第12张图片

2、报文

在http请求和响应的过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第13张图片
3、请求报文

(1)请求方式

  • GET 请求数据
  • POST 发送数据(相对于GET安全一点)

(2)请求地址(RequestURL)
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第14张图片
4、响应报文

(1)http状态码

  • 200请求成功
  • 404请求的资源没有找到
  • 500服务器端错误
  • 400客户端请求语法错误

(2)内容类型

  • text/html
  • text/css
  • application/javascript
  • inage/jpag
  • application/json

三、HTTP请求与响应处理

1、请求参数

客户端向服务器端发送请求时,有时候需要携带一些客户信息,客户信息需要通过请求参数的形式传递到服务器端,比如登录操作。

2、GET请求参数

参数被放置在浏览器地址栏中。

3、POST请求参数

  • 参数被放置在请求体中进行传输
  • 获取POST参数需要使用data事件和end事件
  • 使用querystring系统模块将参数转换为对象格式
    ~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第15张图片
    4、路由

路由是指客户端请求地址与服务器端程序代码的对应关系,即请求什么就响应什么
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第16张图片
核心代码:
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第17张图片
5、静态资源

服务器端不需要处理的,可以直接响应给客户端的资源就是静态资源,例如css、js、image文件

6、动态资源

相同的请求地址不同的响应资源

四、Node.js的工作原理

1、同步API,异步API
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第18张图片

  • 同步API:只有当前执行完成后,才能执行下一步API

  • 异步API:当前API的执行不会阻塞后续代码的执行

2、同步API和异步API区别

  • 返回值, 同步API可以从返回值中拿到API执行的结果,但是异步API是不可以的(默认返回undefined)
    ~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第19张图片
  • 代码执行顺序
  • ~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第20张图片
    3、回调函数

自定义函数让别人去调用
在这里插入图片描述
4、node.js中的异步API
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第21张图片
5、Promise

Promise出现的目的是解决node.js异步编程中回调地狱的问题

let promise = new Promise((resolve,reject) =>{
	setTimeout(() =>{
		if(true){
			resolve({name:'张三'})
		}else{
			reject('失败了')
		}
	},2000);
});
promise.then(result => console.log(result);)
	.catch(error =>console.log(error);)

6、异步函数

异步函数是异步编程语法的终极解决方案,它可以让我们将异步代码写成同步的形式,让代码不再有回调函数嵌套,使代码变得清晰明了
在这里插入图片描述
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第22张图片

第四章 数据库基础

一、数据库概述及环境搭建

1、什么是数据库

数据库即存储数据的仓库,可以将数据进行有序的分门别类的存储。它是独立于语言之外的软件,可以通过API去操作它。
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第23张图片

2、MongoDB数据库的下载安装

在这里插入图片描述
点击通往下载安装MongoDB->MongoDB.
在这里插入图片描述

3、数据库相关概念

在一个数据库软件中可以包含多个数据库,在每一个数据库仓库中可以包含多个数据集合,每个数据集合可以包含多条文档(具体数据)。

术语 解释说明
database 数据库,mongoDB数据库软件中可以建立多个数据库
collection 集合,一组数据的集合,可以理解为javascript中的数组
document 文档,一条具体的数据,可以理解为JavaScript中的对象
field 字段,文档中的属性名称,可以理解为JavaScript中的对象属性

4、Mongoose第三方包

使用node.js操作MongoDB数据库需要依赖的node.js第三方包mongoose
使用npm install mongoose命令下载

5、启动mongodb

在命令行工具(管理员身份)运行net start mongodb即可以mongodb,否则mongodb无法连接

6、数据库连接

使用mongoose提供connect方法即可以连接数据库

//引入
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground')
	.then(()=>console.log('数据库连接成功'))
	.catch(err=>console.log('数据库连接失败',err));

7、创建数据库

在mongodb中不需要显示的创建数据库,如果正在使用的数据库不存在,mongodb会自动创建

二、mongodb增删改查操作

1、创建集合(collection)

创建集合分为两步

  • 一是对集合设定规则
  • 二是创建集合,

创建mongoose.Schema构造函数的实例即可创建集合
语法如下:

//设定集合规则,用Schema
const courseSchema = new mongoose.Schema({
	name:String,
	author:String,
	isPublished:Boolean
});
//创建集合并应用规则
//用mongoose.model创建集合实例,集合名首字母要大写
//这里虽然取得名字是Course,但在数据库中是courses
const Course = mongoose.model('Course',courseSchema);

2、创建文档(document)

创建文档实际上就是向集合中插入数据

方法一:
分为两步:

  • 创建集合实例,即创建文档
  • 调用实例对象下的save方法将数据库保存到数据库中

语法如下:

//创建集合实例
const course = new Course({
    name: 'node.js',
    author: 'hm',
    isPublished: true
})
// 调用实例对象下的save方法将数据库保存到数据库中
course.save();

方法二:
用create方法

Course.create({ name: 'es6', author: 'pink', isPublished: false }, (err, result) => {
    console.log(err);
    console.log(result);
})

和数据库相关的操作都是异步操作
create方法也返回promise对象,所以也可以这样写:

Course.create({ name: 'es6', author: 'pink', isPublished: false })
	.then(doc=>console.log(doc))
	.catch(err=>console.log(err))

3、查询文档

①要查询文档就首先要有足够的数据,所以要先导入数据,语法如下:
mongoimport -d 数据库名称 -c 集合名称 --file 要导入的数据文件

②查询文档

(1)通过find()方法查询

//根据条件查找文档
//find()中语句为空则查找所有文档
Course.find().then(result => console.log(result));
//返回文档集合

当find()中为空时:

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground')
    .then(() => console.log('数据库连接成功'))
    .catch(err => console.log('数据库连接失败', err));

const courseSchema = new mongoose.Schema({
    name: String,
    author: String,
    isPublished: Boolean
});

const Course = mongoose.model('Course', courseSchema);

Course.find().then(result => console.log(result));

执行后结果为:
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第24张图片

将find()中加一个条件{ _id: ‘615aef0b3afad93afa05a9a9’ }:

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground')
    .then(() => console.log('数据库连接成功'))
    .catch(err => console.log('数据库连接失败', err));

const courseSchema = new mongoose.Schema({
    name: String,
    author: String,
    isPublished: Boolean
});

const Course = mongoose.model('Course', courseSchema);

Course.find({ _id: '615aef0b3afad93afa05a9a9' }).then(result => console.log(result));

执行后结果为::
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第25张图片
不管find()查找到一条还是0条还是多条数据,返回的都是数组
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第26张图片

(2)通过findOne()方法查询

findOne()中为空时,默认返回集合中的第一条数据

Course.findOne().then(result => console.log(result));

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第27张图片
findOne()只返回一个数据
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第28张图片
(3)匹配大于 小于 包含 查询字段 排序 限制查询
select(’’)中选择要查询的字段,字段前加-号则为不要查询的字段
sort(’’)按照某一字段排序,默认升序,字段前加-号则为降序
skip()跳过多少条数据,limit限制查询数据
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第29张图片

4、删除文档

①删除单个

Course.findOneAndDelete({条件}).then(result => console.log(result));

查找一条文档并删除
返回删除的文档
如果查询条件匹配了多个文档,那么将会删除第一个匹配的文档

②删除多个

Course.deleteMany({条件}).then(result => console.log(result));

返回结果为删除的个数:
在这里插入图片描述

5、更新文档

①更新单个
如果多个文档都符合查询条件,那也只修改第一个

Course.updateOne({查询条件},{要修改的值}).then(result => console.log(result));

例如:

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground')
    .then(() => console.log('数据库连接成功'))
    .catch(err => console.log('数据库连接失败', err));

const courseSchema = new mongoose.Schema({
    name: String,
    author: String,
    isPublished: Boolean
});

const Course = mongoose.model('Course', courseSchema);

Course.updateOne({ author: 'pink' }, { name: 'html,css,js' }).then(result => console.log(result));

返回结果(修改成功):
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第30张图片
返回结果为一个对象,包含了是否有修改成功的信息

②更新多个

Course.updateMany({查询条件},{要修改的值}).then(result => console.log(result));

例如:

Course.updateMany({},{author: 'pink' }).then(result => console.log(result));

文档中的所有author字段都修改为了pink
在这里插入图片描述

5、mongoose验证

在创建集合规则时,可以设置当前字段的验证规则,验证失败就则输入插入失败。比如设置字符串的长度大于多少小于多少,如果不符合这个要求就验证失败就则输入插入失败。

常用验证规则:

  • required:true 必传字段
const courseSchema = new mongoose.Schema({
    name: {
        type: String,
        //设置集合规则时,将name字段设置为必传字段
        required: true
            //也可以这样写:required: [true, '请输入课程名'],报错时会提示‘请输入课程名’
    },
    author: String,
    isPublished: Boolean
});
//设置了required:true后,下面创建文档就会报错
Course.create({ name: '', author: 'pink', isPublished: false }, (err, result) => {
    console.log(err);
    console.log(result);
})
  • minlength:数值 和 maxlength:数值 字符串的最小值和最大值
const courseSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, '请输入课程名'],
        minlength: [2, '课程名字符串长度请大于2'],
        maxlength: [6, '课程名字符串长度请小于6']
    },
    author: String,
    isPublished: Boolean
});

const Course = mongoose.model('Course', courseSchema);
//下面两个创建就会报错
Course.create({ name: 'a', author: 'pink', isPublished: false }, (err, result) => {
    console.log(err);
    console.log(result);
})
Course.create({ name: 'aaaaaaa', author: 'pink', isPublished: false }, (err, result) => {
    console.log(err);
    console.log(result);
})

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第31张图片

  • trim:true 去除字符串两边的空格
  • min:2 数值最小为2 , max:100 数值最大为100
  • default:xx 默认值
  • enum:[‘html’,‘css’,‘javascript’] 枚举,只能时这三个中的值
  • validate:{} 自定义验证器
validate:{
		validator:v=>{
			//返回一个布尔值
			//true验证成功
			//false验证失败
			//v要验证的值
			return v && v.length>4
		},
		//自定义错误信息
		message:'传递的值不符合验证信息'
 	}

获取验证错误信息:

catch(error => {
	//获取错误信息对象
	const err = error.errors;
	//循环错误信息对象
	for(var attr in err){
		//将错误信息打印到控制台中
		console.log(err[attr]['message']);
	}
})

6、集合关联

通常不同集合的数据之间是有关系的,例如文章信息和用户信息存储在不同集合中,但文章是某个用户发表的,要查询文章的所有信息包括发表用户,就需要用的集合关联

  • 使用_id对集合进行关联
  • 使用populate方法进行关联集合查询
    ~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第32张图片
    首先连接数据库,创建用户集合和文章集合规则:
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/playground')
    .then(() => console.log('数据库连接成功'))
    .catch(err => console.log('数据库连接失败', err));
//用户集合规则
const userSchema = new mongoose.Schema({
    name: String,
    age: Number
});
//文章集合规则
const postSchema = new mongoose.Schema({
    title: String,
    //使用_id对集合进行关联,ref来连接
    author: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User'
    }
});

再创建用户:

User.create({ name: 'hm', age: 23 }).then(result => console.log(result));

在这里插入图片描述

再创建文章:

Post.create({ title: '1233', author: '615c1bea7813d054c2a70505' }).then(result => console.log(result));

在这里插入图片描述
最后使用populate方法进行关联集合查询:

Post.find()
    .populate('author')
    .then((result) => console.log(result));

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第33张图片

第五章 模板引擎

一、模板引擎的基础概念

1、模板引擎

模板引擎是第三方模板
让开发者以更加友好的方式拼接字符串,使项目代码更加清晰,更加易于维护
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第34张图片

2、art-template模板引擎

  • 在命令行工具中使用npm install art-template命令进行下载
  • 使用const template = require(‘art-template’)引入模板引擎
  • 告诉模板引擎要拼接的数据和模板在哪const html = template(‘模板路径’,数据)

3、art-template代码示例

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第35张图片
01.js文件:

//导入模板引擎
const template = require('art-template');
const path = require('path');
//将特定模板与特定数据进行拼接
//模板路径 绝对路径
//要在模板中显示的数据 对象类型
//返回拼接好的字符串
const index = path.join(__dirname, 'index.art');
const html = template(index, {
    data: {
        name: '张三',
        age: 20
    }
});
console.log(html);

index.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>Documenttitle>
head>
<body>
    {{data.name}}
    {{data.age}}
body>
html>

在命令行运行01.js:
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第36张图片

二、模板引擎语法

1、模板语法

  • art-template同时支持两种模板语法:标准语法和原始语法
  • 标准语法可以让模板更容易读写,原始语法具有强大的逻辑处理能力
    标准语法:{{数据}}
    原始语法:<%=数据 %>

2、输出

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第37张图片

3、原文输出

如果数据中携带HTML标签,默认模板引擎不会解析标签,会将其转义后输出
要想原文输出:

  • 标准语法:{{@数据}}
  • 原始语法:<%-数据%>

4、条件判断

在模板中可以根据条件来决定显示哪块HTML代码
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第38张图片

5、循环

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第39张图片
例如:

//导入模板引擎
const template = require('art-template');
const path = require('path');
const index = path.join(__dirname, 'index.art');
const html = template(index, {
    users: [
        'zhangsan',
        'lisi',
        'wangwu'
    ]
});
console.log(html);
<body>
    <ul>
        <% for(var i=0 ;i<users.length;i++){ %>
            <li>
                <%=users[i]%>
            li>
        <% } %>
    ul>
body>

打印结果:
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第40张图片

6、子模板

使用子模板可以将网站公共区块(头部,底部)抽离到单独的文件中
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第41张图片
例如:


<body>
    <% include('./header.art') %>
    <%= msg %>
    <% include('./footer.art') %>
body>

我是头部
//footer.art文件
我是底部
//导入模板引擎
const template = require('art-template');
const path = require('path');
const index = path.join(__dirname, 'index.art');
const html = template(index, {
    msg: '我是首页'
});
console.log(html);

在这里插入图片描述

7、模板继承

使用模板继承可以将html骨架抽离到单独的文件中,其他页面模板可以继承骨架文件
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第42张图片
解决不同文件独有部分:
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第43张图片
{{block ‘名称’}}{{/block}}
{{extend ‘文件路径’}}

模板继承示例:
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第44张图片
在这里插入图片描述
例如:


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>骨架title>
    {{block 'head'}}{{/block}}
head>
<body>
    {{block 'content'}}{{/block}}
body>
html>

{{extend './gujia.art'}} 
{{block 'head'}}
	<link rel="sdfesff" ,href="custom.css"> 
{{/block}} 
{{block 'content'}}
	{{msg}}
{{/block}}
//js文件
//导入模板引擎
const template = require('art-template');
const path = require('path');
const index = path.join(__dirname, 'index.art');
const html = template(index, {
    msg: '我是首页'
});
console.log(html);

打印结果:
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第45张图片

8、模板配置

  • 向模板中导入变量template.defaults.imports.变量名 = 变量值
  • 设置模板根目录 template.defaults.roos = 模板目录
  • 设置模板默认后缀template.defaults.extname = ‘.art’

第六章 Express框架

一、简介与初体验

1、Express框架是什么

Express是一个基于Node平台的web应用开发框架,它提供了一系列强大特性,帮助创建各种web应用。
使用 npm install express 命令下载。

2、Express框架特性

  • 提供了方便简洁的路由定义方式
  • 对获取HTTP请求参数进行了简化处理
  • 对模板引擎支持程度高,方便渲染动态HTML页面
  • 提供了中间件机制有效控制HTTP请求
  • 拥有大量第三方中间件对功能进行扩展

3、原生node.js与Express框架对比之路由

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第46张图片

4、原生node.js与Express框架对比之获取请求参数

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第47张图片
初体验:

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

app.get('/', (req, res) => {
    //send()
    //1.send方法内部会检测响应内容的类型
    //2.send方法会自动设置http状态码
    //3.send方法会自动设置响应的内容类型及编码
    res.send('kuangjia');
});
app.get('/list', (req, res) => {
    res.send({
        name: 'zhangsan',
        age: 20
    })
});
//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

二、中间件

1、什么是中间件

中间件就是一堆方法,可以接收客户端发来的请求、可以对请求做出响应,也可以将请求继续交给下一个中间件继续处理
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第48张图片
中间件主要由两部分组成:中间件方法和请求处理函数
中间件方法由express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理函数
在这里插入图片描述

可以针对同一个请求设置多个中间件,对同一个请求进行多次处理
默认情况下,请求从上到下依次匹配中间件,一旦匹配成功,终止匹配
可以调用next方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第49张图片

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();
app.get('/request', (req, res, next) => {
    req.name = 'zhangsan';
    next();
})
app.get('/request', (req, res) => {
        res.send(req.name)
    })
    //监听端口
app.listen(3000);
console.log('网站服务器启动成功');

2、app.use中间件用法

app.use匹配所有的请求方式,可以直接传入请求处理函数,代表接收所有的请求
在这里插入图片描述
app.use第一个参数也可以传入请求地址,代表不论什么请求方式,只要这个请求地址就接收这个请求
在这里插入图片描述

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();
app.use((req, res, next) => {
    console.log('请求走了app.use中间件');
    next();
})
app.use('/request', (req, res, next) => {
    console.log('请求走了app.use/request中间件');
    next();
})
app.get('/list', (req, res) => {
    res.send('list')
})
app.get('/request', (req, res, next) => {
    req.name = 'zhangsa';
    next();
})
app.get('/request', (req, res) => {
        res.send(req.name)
    })
    //监听端口
app.listen(3000);
console.log('网站服务器启动成功');

3、中间件应用

(1)路由保护,客户端在访问需要登录的页面时,可以先使用中间件判断用户登录状态,用户如果未登录,则拦截请求,直接响应,禁止用户进入需要登录的页面

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();
app.use('/admin', (req, res, next) => {
    let isLogin = true;
    if (isLogin) {
        next();
    } else {
        res.send('请先登录')
    }
});

app.get('/admin', (req, res) => {
    res.send('您已经登录')
});

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

(2)网站维护公告,在所有路由的最上面定义接收所有请求的中间件,直接为客户端做出响应,网站正在维护中

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();
app.use((req, res, next) => {
    res.send('当前网站正在维护。。。')
})
app.use('/admin', (req, res, next) => {
    let isLogin = true;
    if (isLogin) {
        next();
    } else {
        res.send('请先登录')
    }
});

app.get('/admin', (req, res) => {
    res.send('您已经登录')
});

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

(3)自定义404页面

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();
app.use('/admin', (req, res, next) => {
    let isLogin = true;
    if (isLogin) {
        next();
    } else {
        res.send('请先登录')
    }
});

app.get('/admin', (req, res) => {
    res.send('您已经登录')
});
app.use((req, res, next) => {
    //为客户端响应404状态码以及提示信息
    res.status(404).send('当前访问的页面时不存在的');
})

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

4、错误处理中间件

在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取失败,数据库连接失败,错误处理中间件时一个集中处理错误的地方(同步代码)
在这里插入图片描述

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

app.get('/index', (req, res) => {
    //主动抛出一个错误
    throw new Error('程序发生了未知错误')
    res.send('程序正常执行');
})

//错误处理中间件
//err参数就是上面的错误对象
app.use((err, req, res, next) => {
    res.status(500).send(err.message);
})

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

当程序出现错误时,调用next()方法,并且将错误信息通过参数的形式传递给next()方法,即可触发错误处理中间件(异步代码)
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第50张图片

//引入express框架
const express = require('express');
const fs = require('fs');
//创建网站服务器
const app = express();

app.get('/index', (req, res, next) => {
    fs.readFile('./demo.text', 'utf-8', (err, result) => {
        if (err != null) {
            //传递了参数就代表要触发错误处理中间件
            next(err);
        } else {
            res.send(result);
        }
    })
})

//错误处理中间件
//err参数就是上面的错误对象
app.use((err, req, res, next) => {
    res.status(500).send(err.message);
})

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

5、捕获错误

在node.js中,异步API的错误信息都是通过回调函数获取的,支持Promise对象的异步API发生错误可以通过catch方法捕获。

异步函数执行如果发生错误如何捕获错误呢?
try catch可以捕获异步函数以及其他同步代码在执行过程中发生的错误信息,但是不能捕获其他类型的API发生的错误
在这里插入图片描述

//引入express框架
const express = require('express');
const fs = require('fs');
const promisify = require('util').promisify;
const readFile = promisify(fs.readFile);
//创建网站服务器
const app = express();

app.get('/index', async(req, res, next) => {
    try {
        await readFile('./aaa.js');
    } catch (error) {
        next(error);
    }
})

//错误处理中间件
//err参数就是上面的错误对象
app.use((err, req, res, next) => {
    res.status(500).send(err.message);
})

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

三、Express请求处理

1、创建模块化路由

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第51张图片

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

//用Router()方法创建一个路由对象
const home = express.Router();
//为路由对象匹配请求路径
app.use('/home', home);
//创建二级路由
home.get('/index', (req, res) => {
    res.send('欢迎来到博客首页页面')
})

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

2、构建模块化路由

在这里插入图片描述

//route/admin.js
const express = require('express');

const admin = express.Router();

admin.get('/index', (req, res) => {
    res.send('欢迎来到博客管理页面');
})

module.exports = admin;
//route/home.js
const express = require('express');

const home = express.Router();

home.get('/index', (req, res) => {
    res.send('欢迎来到博客首页页面');
})

module.exports = home;
//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

const home = require('./route/home');
const admin = require('./route/admin');

app.use('/home', home);
app.use('/admin', admin);

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

3、GET参数的获取

Express框架使用req.query即可获取GET参数,框架内部会将GET参数转换为对象并返回
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第52张图片

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

app.get('/index', (req, res) => {
    //获取get请求参数
    res.send(req.query);
})

//监听端口
app.listen(3000);
console.log('网站服务器启动成功');

在浏览器输入如下:
在这里插入图片描述
则会响应:
在这里插入图片描述

4、POST请求参数

Express中接收post请求参数需要借助第三方包body-parser(目前已被被弃用)
~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第53张图片

(express 最新版内置了post参数解析,可以直接调用body-parser,不用引入body-parser了,直接app.use(express.urlencoded({extended:false})))
如下:

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

//拦截所有请求
//extended:false 方法内部使用querystring模块处理请求参数的格式
//extended:true 方法内部使用第三方模块qs处理请求参数的格式
app.use(express.urlencoded({ extended: false }))
app.post('/add', (req, res) => {
        //接收post请求参数
        res.send(req.body)
    })
    //监听端口
app.listen(3000);
console.log('网站服务器启动成功');

通过表单来从客户端发送post请求:

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>Documenttitle>
head>

<body>
    <form action="http://localhost:3000/add" method="post">
        <input type="text" name="username">
        <input type="password" name="password">
        <input type="submit">
    form>
body>

html>

在这里插入图片描述
提交后响应了获取的post请求参数:
在这里插入图片描述
app.use方法疑惑:
app.use方法需要传递一个请求处理函数进去,但是app.use(express.urlencoded({ extended: false }))为什么传递了一个方法的调用呢?
在这里插入图片描述
实际上调用的这个方法的返回值也是一个函数,返回的函数正好作为了app.use的参数,例如如下:

//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

//传递了一个方法的调用
app.use(fn())

//这个方法的返回值也是一个函数,返回的函数正好作为了app.use的参数
function fn() {
    return function(req, res, next) {
        console.log(req.method);
        next();
    }
}

app.get('/', (req, res) => {
        res.send('ok')
    })
    //监听端口
app.listen(3000);
console.log('网站服务器启动成功');

这个方法也可以传参数:

app.use(fn({ a: 1 }))
function fn(obj) {
    return function(req, res, next) {
        if (obj.a != 1) {
            console.log(req.url);
        } else {
            console.log(req.method);
        }
        next();
    }
}

5、Express路由参数

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第54张图片

6、静态资源的处理

通过Express内置的express.static可以方便地托管静态文件,例如img,css,js文件等。

app.use(express.static('public');

~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第55张图片

7、express模板引擎

  • 为了使art-template模板引擎能够更好的和Express框架配合,模板引擎官方在原art-template模板引擎的基础上封装了express-art-template
  • 使用npm install art-template express-art-template命令下载安装
    ~【笔记】黑马node.js(p1~p94node.js部分)笔记~_第56张图片
//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

const path = require('path');

//1、告诉express框架使用什么模板引擎渲染什么后缀的模板文件
app.engine('art', require('express-art-template'))
    //2、告诉express框架模板存放的位置是什么
app.set('views', path.join(__dirname, 'views'))
    //3、告诉express框架模板默认后缀是什么
app.set('view engine', 'art')

app.get('/index', (req, res) => {
        res.render('index', {
            //render方法:
            //1、拼接模板路径
            //2、拼接模板后缀
            //3、哪个模板和哪个数据进行拼接
            //4、将拼接结果响应给了客户端
            msg: 'message'
        })
    })
    //监听端口
app.listen(3000);
console.log('网站服务器启动成功');

此时在views中建一个art文件:

{{msg}}

浏览器上在会响应message

  • app.locals对象
    将变量设置到app.locals对象下面,这个数据在所有的模板中都可以获取到
    例如,将上面的js文件写一个app.locals对象下面的变量:
//引入express框架
const express = require('express');
//创建网站服务器
const app = express();

const path = require('path');

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

//将变量设置到app.locals对象下面,这个数据在所有的模板中都可以获取到
app.locals.users = [{
    name: 'zhangsan',
    age: 20
}, {
    name: 'lisi',
    age: 30
}]
app.get('/index', (req, res) => {
        res.render('index', {
            msg: 'message'
        })
    })
    //监听端口
app.listen(3000);
console.log('网站服务器启动成功');

然后:index.art文件(其他文件也可以访问app.locals对象下的变量):

{{msg}}
<ul>
    {{each users}}
    <li>
        {{$value.name}} {{$value.age}}
    li>
    {{/each}}
ul>

浏览器上响应为
在这里插入图片描述

你可能感兴趣的:(前端学习笔记,node.js,javascript,前端)