Node 介绍 base LPZ
链接 https://www.yuque.com/lipengz…
链接 2 https://lurongtao.gitee.io/fe…
- Node.js 是 JavaScript 运行时
- 通俗易懂的讲,Node.js 是 JavaScript 的运行平台
- Node.js 既不是语言,也不是框架,它是一个平台
-
浏览器中的 JavaScript
-
EcmaScript
- 根本语法
- if
- var
- function
- Object
- Array
- Bom
- Dom
-
-
Node.js 中的 JavaScript
- 没有 Bom,Dom
- EcmaScript
-
在 Node 中这个 JavaScript 执行环境为 JavaScript 提供了一些服务器级别的 API
- 例如文件的读写
- 网络服务的构建
- 网络通信
- http 服务器
-
构建与 Chrome 的 V8 引擎之上
- 代码只是具备特定格局的字符串
- 引擎能够意识它,帮你解析和执行
- Google Chrome 的 V8 引擎是目前公认的解析执行 JavaScript 代码最快的
- Node.js 的作者把 Google Chrome 中的 V8 引擎移植进去,开发了一个独立的 JavaScript 运行时环境
-
Node.js uses an envent-driven,non-blocking I/O mode that makes it lightweight and efficent.
- envent-driven 事件驱动
- non-blocking I/O mode 非阻塞 I / O 模型(异步)
- ightweight and efficent. 轻量和高效
- 单线程 跨平台
-
Node.js package ecosystem,npm,is the larget scosystem of open sourcr libraries in the world
- npm 是世界上最大的开源生态系统
- 绝大多数 JavaScript 相干的包都寄存在 npm 上,这样做的目标是为了让开发人员更不便的去下载应用
- npm install jquery
- JavaScript 长久以来始终被限度在浏览器的沙箱中运行,它的能力取决于浏览器中间层提供的反对多少。Node 将高性能的 V8 带到了服务器端,使 JavaScript 也能够开发出实时高性能的服务器。在 Node 中,不再与 CSS 样式表,DOM 树打交道,能够随便的拜访本地文件,搭建 WebSocket 服务器,连贯数据库等零碎级底层操作。Node 不解决 UI,只关怀数据,无论是本地数据还是网络数据。前后端编程对立,大大降低了前后端编程切换的代码。对于前端工程师而言,本人相熟的 JavaScript 现在居然能够在另一个中央大放异彩,不谈其余起因,仅仅因为好奇,也值得去关注和探索它。
Node 运行机制
Node 能做什么
- web 服务器后盾
-
命令行工具
- npm(node)
- git(c 语言)
- hexo(node)
- …
-
对于前端工程师来讲,接触最多的是它的命令行工具
- 本人写的很少,次要是用他人第三方的
- webpack
- gulp
- npm
相干链接
● Node.js 官网文档
https://nodejs.org/en/docs/
● Node.js 中文文档(非官方)
http://nodejs.cn/
● 深入浅出 Node.js
https://read.douban.com/ebook…
● Node.js 权威指南
https://book.douban.com/subje…
● Node.js 实战
https://book.douban.com/subje…
● Node.js 实战
https://book.douban.com/subje…
● Node.js 实战(第 2 季)
https://book.douban.com/subje…
● Node.js 中文社区
http://cnodejs.org/
● Node.js 包教不包会
https://github.com/alsotang/n…
● EcmaScript 6 入门
http://es6.ruanyifeng.com/
● 七天学会 NodeJS
https://github.com/nqdeng/7-d…
起步
装置 Node 环境
- 查看 Node 环境的版本号
- 下载:https://nodejs.org/en/
-
装置:
- 傻瓜式装置,一路
next
- 装置过再次装置会降级
- 傻瓜式装置,一路
-
确认 Node 环境是否装置胜利
- 查看 node 的版本号:
node --version
- 或者
node -v
- 查看 node 的版本号:
- 配置环境变量
解析执行 JavaScript
- 创立编写 JavaScript 脚本文件
- 关上终端,定位脚本文件的所属目录
- 输出
node 文件名
执行对应的文件
留神:文件名不要用 node.js
来命名,也就是说除了 node
这个名字轻易起,最好不要应用中文。
文件的读写
文件读取:
// 浏览器中的 JavaScript 是没有文件操作能力的
// 然而 Node 中的 JavaScript 具备文件操作能力
//fs 是 file-system 的简写,就是文件系统的意思
// 在 Node 中如果想要进行文件的操作就必须援用 fs 这个外围模块
// 在 fs 这个和兴模块中,就提供了人所有文件操作相干的 API
// 例如 fs.readFile 就是用来读取文件的
// 1. 应用 fs 外围模块
var fs = require('fs');
// 2. 读取文件
fs.readFile('./data/a.txt',function(err,data){if(err){console.log('文件读取失败');
}
else{console.log(data.toString());
}
})
文件写入:
// 1. 应用 fs 外围模块
var fs = require('fs');
// 2. 将数据写入文件
fs.writeFile('./data/a.txt','我是文件写入的信息',function(err,data){if(err){console.log('文件写入失败');
}
else{console.log(data.toString());
}
})
http
服务器:
// 1. 加载 http 外围模块
var http = require('http');
// 2. 应用 http.createServer()创立一个 web 服务器
var server = http.createServer();
// 3. 服务器要做的事儿
// 提供服务:对数据服务
// 发申请
// 接管申请
// 解决申请
// 反馈(发送响应)// 当客户端申请过去,就会主动触发服务器的 request 申请事件,而后执行第二个参数:回调处理函数
server.on('request',function(){console.log('收到客户的申请了')
})
// 4. 绑定端口号,启动服务
server.listen(3000,function(){console.log('runing...')
})
Node.js 中的 JavaScript
ECMAScript
全局成员
https://nodejs.org/dist/lates…
模块化
Node 中的模块零碎
应用 Node 编写应用程序次要就是在应用:
-
EcmaScript 语言
- 和浏览器一样,在 Node 中没有 Bom 和 Dom
-
外围模块
- 文件操作的 fs
- http 服务操作的 http
- url 门路操作模块
- path 门路解决模块
- os 操作系统信息
-
第三方模块
- art-template
- 必须通过 npm 来下载才能够应用
-
本人写的模块
- 本人创立的文件
什么是模块化
- 文件作用域(模块是独立的,在不同的文件应用必须要从新援用)【在 node 中没有全局作用域,它是文件模块作用域】
-
通信规定
- 加载 require
- 导出 exports
CommonJS 模块标准
在 Node 中的 JavaScript 还有一个重要的概念,模块零碎。
- 模块作用域
- 应用 require 办法来加载模块
-
应用 exports 接口对象来导出模板中的成员
加载
require
语法:
var 自定义变量名 = require('模块')
作用:
- 执行被加载模块中的代码
- 失去被加载模块中的
exports
导出接口对象
导出
exports
- Node 中是模块作用域,默认文件中所有的成员只在以后模块无效
-
对于心愿能够被其余模块拜访到的成员,咱们须要把这些公开的成员都挂载到
exports
接口对象中就能够了导出多个成员(必须在对象中):
exports.a = 123; exports.b = function(){console.log('bbb') }; exports.c = {foo:"bar"}; exports.d = 'hello';
导出单个成员(拿到的就是函数,字符串):
module.exports = 'hello';
以下状况会笼罩:
module.exports = 'hello'; // 后者会笼罩前者 module.exports = function add(x,y) {return x+y;}
也能够通过以下办法来导出多个成员:
module.exports = { foo = 'hello', add:function(){return x+y;} };
模块原理
exports 和 module.exports
的一个援用:
console.log(exports === module.exports); //true
exports.foo = 'bar';
// 等价于
module.exports.foo = 'bar';
当给 exports 从新赋值后,exports!= module.exports.
最终 return 的是 module.exports, 无论 exports 中的成员是什么都没用。真正去应用的时候:导出单个成员:exports.xxx = xxx;
导出多个成员:module.exports 或者 modeule.exports = {};
总结
// 援用服务
var http = require('http');
var fs = require('fs');
// 援用模板
var template = require('art-template');
// 创立服务
var server = http.createServer();
// 公共门路
var wwwDir = 'D:/app/www';
server.on('request', function (req, res) {
var url = req.url;
// 读取文件
fs.readFile('./template-apche.html', function (err, data) {if (err) {return res.end('404 Not Found');
}
fs.readdir(wwwDir, function (err, files) {if (err) {return res.end('Can not find www Dir.')
}
// 应用模板引擎解析替换 data 中的模板字符串
// 去 xmpTempleteList.html 中编写模板语法
var htmlStr = template.render(data.toString(), {
title: 'D:/app/www/ 的索引',
files:files
});
// 发送响应数据
res.end(htmlStr);
})
})
});
server.listen(3000, function () {console.log('running....');
})
1.jQuery 中的 each 和 原生 JavaScript 办法 forEach 的区别:提供源头:原生 js 是 es5 提供的(不兼容 IE8),
jQuery 的 each 是 jQuery 第三方库提供的(如果要应用须要用 2 以下的版本也就是 1. 版本), 它的 each 办法次要用来遍历 jQuery 实例对象(伪数组), 同时也能够做低版本 forEach 的替代品,jQuery 的实例对象不能应用 forEach 办法,如果想要应用必须转为数组([].slice.call(jQuery 实例对象))能力应用
2. 模块中导出多个成员和导出单个成员
3.301 和 302 的区别:301 永恒重定向, 浏览器会记住
302 长期重定向
4.exports 和 module.exports 的区别:
每个模块中都有一个 module 对象
module 对象中有一个 exports 对象
咱们能够把须要导出的成员都挂载到 module.exports 接口对象中
也就是 `module.exports.xxx = xxx` 的形式
然而每次写太多了就很麻烦,所以 Node 为了简化代码,就在每一个模块中都提供了一个成员叫 `exports`
`exports === module.exports` 后果为 true, 所以齐全能够 `exports.xxx = xxx`
当一个模块须要导出单个成员的时候必须应用 `module.exports = xxx` 的形式,=, 应用 `exports = xxx` 不论用, 因为每个模块最终 return 的是 module.exports, 而 exports 只是 module.exports 的一个援用, 所以 `exports` 即便从新赋值, 也不会影响 `module.exports`。有一种赋值形式比拟非凡:`exports = module.exports` 这个用来新建设援用关系的。
require 的加载规定
-
外围模块
- 模块名
-
第三方模块
- 模块名
-
用户本人写的
- 门路
require 的加载规定:
- 优先从缓存加载
-
判断模块标识符
- 外围模块
- 本人写的模块(门路模式的模块)
-
第三方模块(node_modules)
- 第三方模块的标识就是第三方模块的名称(不可能有第三方模块和外围模块的名字统一)
-
npm
- 开发人员能够把写好的框架库公布到 npm 上
- 使用者通过 npm 命令来下载
-
应用形式:
var 名称 = require('npm install【下载包】的包名')
- node_modules/express/package.json main
- 如果 package.json 或者 main 不成立,则查找被选择项:index.js
- 如果以上条件都不满足,则持续进入上一级目录中的 node_modules 依照下面的规定顺次查找,直到以后文件所属此盘根目录都找不到最初报错
// 如果非门路模式的标识
// 门路模式的标识:// ./ 当前目录 不可省略
// ../ 上一级目录 不可省略
// /xxx 也就是 D:/xxx
// 带有绝对路径简直不必(D:/a/foo.js)// 首位示意的是以后文件模块所属磁盘根目录
// require('./a');
// 外围模块
// 外围模块实质也是文件,外围模块文件曾经被编译到了二进制文件中了,咱们只须要依照名字来加载就能够了
require('fs');
// 第三方模块
// 但凡第三方模块都必须通过 npm 下载(npm i node_modules),应用的时候就能够通过 require('包名')来加载才能够应用
// 第三方包的名字不可能和外围模块的名字是一样的
// 既不是外围模块,也不是门路模式的模块
// 先找到以后文所述目录的 node_modules
// 而后找 node_modules/art-template 目录
// node_modules/art-template/package.json
// node_modules/art-template/package.json 中的 main 属性
// main 属性记录了 art-template 的入口模块
// 而后加载应用这个第三方包
// 实际上最终加载的还是文件
// 如果 package.json 不存在或者 mian 指定的入口模块不存在
// 则 node 会主动找该目录下的 index.js
// 也就是说 index.js 是一个备选项,如果 main 没有指定,则加载 index.js 文件
//
// 如果条件都不满足则会进入上一级目录进行查找
// 留神:一个我的项目只有一个 node_modules,放在我的项目根目录中,子目录能够间接调用根目录的文件
var template = require('art-template');
模块标识符中的 /
和文件操作门路中的/
文件操作门路:
// 咱们所应用的所有文件操作的 API 都是异步的
// 就像 ajax 申请一样
// 读取文件
// 文件操作中 ./ 相当于以后模块所处磁盘根目录
// ./index.txt 绝对于当前目录
// /index.txt 绝对于当前目录
// /index.txt 绝对路径, 以后文件模块所处根目录
// d:express/index.txt 绝对路径
fs.readFile('./index.txt',function(err,data){if(err){return console.log('读取失败');
}
console.log(data.toString());
})
模块操作门路:
// 在模块加载中,相对路径中的./ 不能省略
// 这里省略了. 也是磁盘根目录
require('./index')('hello')
服务端渲染以及客户端渲染
- 简略来说,在服务端应用模板引擎就是服务端渲染, 只须要申请一次。服务端会把 html 文件渲染好。所以速度更快.
-
客户端渲染
浏览器申请,在服务端寄存的一个 html 文件。蕴含 ajax 以及模板渲染语法,浏览器申请后,失去服务器响应的字符串了。解析文件后。发现 script 以及 ajax 等 再次向服务器申请,失去服务器的响应数据后,最终应用模板引擎来替换显示在界面 ….. 问题是页面响应了,然而数据量大的话,可能会呈现白屏 …
script link img iframe audio vedio 等具备外链的资源标签 src link 的 href 属性时浏览器会再次申请 a 链接的 href 属性不会立刻申请是须要点击的
-
分别渲染形式
关上网页源代码,能够看到的就是服务端渲染的,客户端后续增加上的是没法看见的 …. 还有一个特色,会产生刷新 点击下一步后你会发现刷新这种的就是服务端渲染。前端个别是异步无刷新,只是部分更新
- 这里为什么须要两种 客户 ajax 异步渲染不利于 seo 不易于搜素引擎爬虫到。。。
npm
- node package manage(node 包管理器)
- 通过 npm 命令装置 jQuery 包(npm install –save jquery),在装置时加上 –save 会被动生成说明书文件信息(将安装文件的信息增加到 package.json 外面)
npm 网站
npmjs.com 网站 是用来搜寻 npm 包的
npm 命令行工具
npm 是一个命令行工具,只有装置了 node 就曾经装置了 npm。
npm 也有版本概念,能够通过 npm --version
来查看 npm 的版本
降级 npm(本人降级本人):
npm install --global npm
常用命令
-
npm init(生成 package.json 说明书文件)
- npm init -y(能够跳过向导,疾速生成)
-
npm install
- 一次性把 dependencies 选项中的依赖项全副装置
- 简写(npm i)
- 该命令在哪执行 就会在当前目录生成一个 node_modules 文件夹 并将文件放进去
-
npm install 包名
- 只下载指定包
- 简写(npm i 包名)
-
npm install –save 包名
- 下载并且保留依赖项(package.json 文件中的 dependencies 选项)
- 简写(npm i 包名)
-
npm uninstall 包名
- 只删除,如果有依赖项会仍然保留
- 简写(npm un 包名)
-
npm uninstall –save 包名
- 删除的同时也会把依赖信息全副删除
- 简写(npm un 包名)
-
npm help
- 查看应用帮忙
-
npm 命令 –help
- 查看具体命令的应用帮忙(npm uninstall –help)
解决 npm 被墙问题
npm 存储包文件的服务器在国外,有时候会被墙,速度很慢,所以须要解决这个问题。
https://developer.aliyun.com/… 淘宝的开发团队把 npm 在国内做了一个镜像(也就是一个备份)。
装置淘宝的 cnpm:
npm install -g cnpm --registry=https://registry.npm.taobao.org;
#在任意目录执行都能够
#--global 示意装置到全局,而非当前目录
#--global 不能省略,否则不论用
npm install --global cnpm
安装包的时候把以前的 npm
替换成cnpm
。
# 走国外的 npm 服务器下载 jQuery 包,速度比较慢
npm install jQuery;
#应用 cnpm 就会通过淘宝的服务器来下载 jQuery
cnpm install jQuery;
如果不想装置 cnpm
又想应用淘宝的服务器来下载:
npm install jquery --registry=https://npm.taobao.org;
然而每次手动加参数就很麻烦,所以咱们能够把这个选项退出到配置文件中:
npm config set registry https://npm.taobao.org;
#查看 npm 配置信息
npm config list;
只有通过下面的配置命令,则当前所有的 npm install
都会通过淘宝的服务器来下载
package.json
每一个我的项目都要有一个 package.json
文件(包形容文件,就像产品的说明书一样)
这个文件能够通过 npm init
主动初始化进去
D:\code\node 中的模块零碎 >npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (node 中的模块零碎)
Sorry, name can only contain URL-friendly characters.
package name: (node 中的模块零碎) cls
version: (1.0.0)
description: 这是一个测试项目
entry point: (main.js)
test command:
git repository:
keywords:
author: xiaochen
license: (ISC)
About to write to D:\code\node 中的模块零碎 \package.json:
{
"name": "cls",
"version": "1.0.0",
"description": "这是一个测试项目",
"main": "main.js",
"scripts": {"test": "echo \"Error: no test specified\"&& exit 1"},
"author": "xiaochen",
"license": "ISC"
}
Is this OK? (yes) yes
对于目前来讲,最有用的是 dependencies
选项,能够用来帮忙咱们保留第三方包的依赖信息。
如果 node_modules
删除了也不必放心,只须要在控制面板中 npm install
就会主动把 package.json
中的 dependencies
中所有的依赖项全副都下载回来。
- 倡议每个我的项目的根目录下都有一个
package.json
文件 - 倡议执行
npm install 包名
的时候都加上--save
选项,目标是用来保留依赖信息
package.json 和 package-lock.json
npm 5 以前是不会有 package-lock.json
这个文件
npm5 当前才退出这个文件
当你安装包的时候,npm 都会生成或者更新 package-lock.json
这个文件
- npm5 当前的版本装置都不要加
--save
参数,它会主动保留依赖信息 - 当你安装包的时候,会主动创立或者更新
package-lock.json
文件 -
package-lock.json
这个文件会蕴含
node_modules
中所有包的信息(版本,下载地址。。。)
- 这样的话从新
npm install
的时候速度就能够晋升
- 这样的话从新
-
从文件来看,有一个
lock
称之为锁
- 这个
lock
应用来锁版本的 - 如果我的项目依赖了
1.1.1
版本 - 如果你从新 install 其实会下载最细版本,而不是
1.1.1
package-lock.json
的另外一个作用就是锁定版本号,避免主动降级
path 门路操作模块
参考文档:https://nodejs.org/docs/lates…
- 这个
- path.basename:获取门路的文件名,默认蕴含扩展名
- path.dirname:获取门路中的目录局部
- path.extname:获取一个门路中的扩展名局部
-
path.parse:把门路转换为对象
- root:根门路
- dir:目录
- base:蕴含后缀名的文件名
- ext:后缀名
- name:不蕴含后缀名的文件名
- path.join:拼接门路
-
path.isAbsolute:判断一个门路是否为绝对路径[![image-20200315150610001]()](https://github.com/smallC-L-Y… 学习笔记.md)
Node 中的其它成员(__dirname,__filename)
在每个模块中,除了
require
,exports
等模块相干的 API 之外,还有两个非凡的成员: __dirname
,是一个成员,能够用来 动静 获取以后文件模块所属目录的绝对路径__filename
,能够用来 动静 获取以后文件的绝对路径(蕴含文件名)-
__dirname
和filename
是不受执行 node 命令所属门路影响的[![image-20200315151551873]()](https://github.com/smallC-L-Y… 学习笔记.md)
在文件操作中,应用相对路径是不牢靠的,因为 node 中文件操作的门路被设计为绝对于执行 node 命令所处的门路。
所以为了解决这个问题,只须要把相对路径变为绝对路径(绝对路径不受任何影响)就能够了。
就能够应用
__dirname
或者__filename
来帮忙咱们解决这个问题在拼接门路的过程中,为了防止手动拼接带来的一些低级谬误,举荐应用
path.join()
来辅助拼接var fs = require('fs'); var path = require('path');
// console.log(__dirname + ‘a.txt’);
// path.join 办法会将文件操作中的相对路径都对立的转为动静的绝对路径
fs.readFile(path.join(__dirname + ‘/a.txt’),’utf8′,function(err,data){
if(err){throw err}
console.log(data);
});
> 补充:模块中的门路标识和这里的门路没关系,不受影响(就是绝对于文件模块)> ** 留神:**
>
> ** 模块中的门路标识和文件操作中的相对路径标识不统一 **
>
> ** 模块中的门路标识就是绝对于以后文件模块,不受 node 命令所处门路影响 **
# Express(疾速的)作者:Tj
原生的 http 在某些方面体现不足以应答咱们的开发需要,所以就须要应用框架来放慢咱们的开发效率,框架的目标就是提高效率,让咱们的代码高度对立。在 node 中有很多 web 开发框架。次要学习 express
- `http://expressjs.com/`, 其中次要封装的是 http。- ```
// 1 装置
// 2 引包
var express = require('express');
// 3 创立服务器应用程序 也就是原来的 http.createServer();
// 相当于以前的创立 server
var app = express();
// 公开指定目录
// 只有通过这样做了,就能够通过 /public/xx 的形式来拜访 public 目录中的所有资源
// 在 Express 中凋谢资源就是一个 API 的事
app.use('/public/',express.static('/public/'));
// 模板引擎在 Express 中凋谢模板也是一个 API 的事
// 当服务器收到申请形式为 get 且地址为 / 的时候,执行回调处理函数
// 再也不须要你在本人判断 url
app.get('/',function(req,res){// 不举荐应用以前的 res.write () res.end()
// 不必放心你的 content type 中文 end 会有乱码 send 就不会
res.send('hello express');
})
// 相当于 server.listen
app.listen(3000,function(){console.log('app is runing at port 3000');
})
学习 Express
起步
装置:[![image-20200310123723079]()](https://github.com/smallC-L-Y… 学习笔记.md)
cnpm install express
hello world:[![image-20200310124850557]()](https://github.com/smallC-L-Y… 学习笔记.md)
// 引入 express
var express = require('express');
// 1. 创立 app
var app = express();
// 2.
app.get('/',function(req,res){
// 1
// res.write('Hello');
// res.write('World');
// res.end()
// 1 还能够写成 2
// res.end('hello world');
// 3 是 express 中的写法 不必判断响应头 而且 express 内置了错误处理 申请不存在的 url 状态码是 404 且内容为 cant ....
res.send('hello world');
})
app.listen(3000,function(){console.log('express app is runing...');
})
根本路由
路由:
- 申请办法
- 申请门路
- 申请处理函数
get:
// 当你以 get 办法申请 / 的时候,执行对应的处理函数
app.get('/',function(req,res){res.send('hello world');
})
post:
// 当你以 post 办法申请 / 的时候,执行对应的处理函数
app.post('/',function(req,res){res.send('hello world');
})
Express 动态服务 API 凋谢动态资源
// app.use 不仅仅是用来解决动态资源的,还能够做很多工作(body-parser 的配置)
app.use(express.static('public'));
app.use(express.static('files'));
// 公开 public 目录
app.use('/stataic',express.static('public'));
// 引入 express
var express = require('express');
// 创立 app
var app = express();
// 凋谢动态资源
// 1. 当以 /public/ 结尾的时候,去./public/ 目录中找对应资源
// 拜访:http://127.0.0.1:3000/public/login.html
app.use('/public/',express.static('./public/'));
// 2. 当省略第一个参数的时候,能够通过省略 /public 的形式来拜访
// 拜访:http://127.0.0.1:3000/login.html
// app.use(express.static('./public/'));
// 3. 拜访:http://127.0.0.1:3000/a/login.html
// a 相当于 public 的别名
// app.use('/a/',express.static('./public/'));
//
app.get('/',function(req,res){res.end('hello world');
});
app.listen(3000,function(){console.log('express app is runing...');
});
在 Express 中配置应用 art-templete
模板引擎
- art-template 官网文档
-
在 node 中,有很多第三方模板引擎都能够应用,不是只有
art-template
- 还有 ejs,jade(pug),handlebars,nunjucks
装置:
npm install --save art-template
npm install --save express-art-template
// 两个一起装置
npm i --save art-template express-art-template
配置:
app.engine('html', require('express-art-template'));
应用:
app.get('/',function(req,res){
// express 默认会去 views 目录找 index.html
res.render('index.html',{title:'hello world'});
})
如果心愿批改默认的 views
视图渲染存储目录,能够:
// 第一个参数 views 千万不要写错
app.set('views', 目录门路);
在 Express 中获取表单申请数据
获取 get 申请数据:
Express 内置了一个 api,能够间接通过 req.query
来获取数据
// 通过 requery 办法获取用户输出的数据
// req.query 只能拿到 get 申请的数据
var comment = req.query;
获取 post 申请数据:
在 Express 中没有内置获取表单 post 申请体的 api,这里咱们须要应用一个第三方包 body-parser
来获取数据。
装置:
npm install --save body-parser;
配置:
// 配置解析表单 POST 申请体插件(留神:肯定要在 app.use(router) 之前)
var express = require('express')
// 引包
var bodyParser = require('body-parser')
var app = express()
// 配置 body-parser
// 只有退出这个配置,则在 req 申请对象上会多进去一个属性:body
// 也就是说能够间接通过 req.body 来获取表单 post 申请数据
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false}))
// parse application/json
app.use(bodyParser.json())
应用:
app.use(function (req, res) {res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
// 能够通过 req.body 来获取表单申请数据
res.end(JSON.stringify(req.body, null, 2))
})
在 Express 中配置应用 express-session
插件操作
参考文档:https://github.com/expressjs/…
装置:
npm install express-session
配置:
// 该插件会为 req 申请对象增加一个成员:req.session 默认是一个对象
// 这是最简略的配置形式
//Session 是基于 Cookie 实现的
app.use(session({
// 配置加密字符串,他会在原有的根底上和字符串拼接起来去加密
// 目标是为了减少安全性,避免客户端歹意伪造
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,// 无论是否实用 Session,都默认间接调配一把钥匙
cookie: {secure: true}
}))
应用:
// 读
// 增加 Session 数据
//session 就是一个对象
req.session.foo = 'bar';
// 写
// 获取 session 数据
req.session.foo
// 删
req.session.foo = null;
delete req.session.foo
提醒:
默认 Session 数据时内存储数据,服务器一旦重启,真正的生产环境会把 Session 进行长久化存储。
利用 Express 实现 ADUS 我的项目
模块化思维
模块如何划分:
- 模块职责要繁多
javascript 模块化:
- Node 中的 CommonJS
-
浏览器中的:
- AMD require.js
- CMD sea.js
- es6 中减少了官网反对
起步
- 初始化
- 模板解决
路由设计
申请办法 | 申请门路 | get 参数 | post 参数 | 备注 |
---|---|---|---|---|
GET | /students | 渲染首页 | ||
GET | /students/new | 渲染增加学生页面 | ||
POST | /students/new | name,age,gender,hobbies | 解决增加学生申请 | |
GET | /students/edit | id | 渲染编辑页面 | |
POST | /students/edit | id,name,age,gender,hobbies | 解决编辑申请 | |
GET | /students/delete | id | 解决删除申请 |
提取路由模块
router.js:
/**
* router.js 路由模块
* 职责:* 解决路由
* 依据不同的申请办法 + 申请门路设置具体的申请函数
* 模块职责要繁多,咱们划分模块的目标就是加强代码的可维护性,晋升开发效率
*/
var fs = require('fs');
// Express 专门提供了一种更好的形式
// 专门用来提供路由的
var express = require('express');
// 1 创立一个路由容器
var router = express.Router();
// 2 把路由都挂载到路由容器中
router.get('/students', function(req, res) {// res.send('hello world');
// readFile 的第二个参数是可选的,传入 utf8 就是通知他把读取到的文件间接依照 utf8 编码,间接转成咱们意识的字符
// 除了这样来转换,也能够通过 data.toString()来转换
fs.readFile('./db.json', 'utf8', function(err, data) {if (err) {return res.status(500).send('Server error.')
}
// 读取到的文件数据是 string 类型的数据
// console.log(data);
// 从文件中读取到的数据肯定是字符串,所以肯定要手动转换成对象
var students = JSON.parse(data).students;
res.render('index.html', {
// 读取文件数据
students:students
})
})
});
router.get('/students/new',function(req,res){res.render('new.html')
});
router.get('/students/edit',function(req,res){});
router.post('/students/edit',function(req,res){});
router.get('/students/delete',function(req,res){});
// 3 把 router 导出
module.exports = router;
app.js:
var router = require('./router');
// router(app);
// 把路由容器挂载到 app 服务中
// 挂载路由
app.use(router);
设计操作数据的 API 文件模块
es6 中的 find 和 findIndex:
find 承受一个办法作为参数,办法外部返回一个条件
find 会便当所有的元素,执行你给定的带有条件返回值的函数
合乎该条件的元素会作为 find 办法的返回值
如果遍历完结还没有合乎该条件的元素,则返回 undefined[![image-20200313103810731]()](https://github.com/smallC-L-Y… 学习笔记.md)
/**
* student.js
* 数据操作文件模块
* 职责:操作文件中的数据,只解决数据,不关怀业务
*/
var fs = require('fs');
/**
* 获取所有学生列表
* return []
*/
exports.find = function(){}
/**
* 获取增加保留学生
*/
exports.save = function(){}
/**
* 更新学生
*/
exports.update = function(){}
/**
* 删除学生
*/
exports.delete = function(){}
步骤
- 解决模板
- 配置动态凋谢资源
- 配置模板引擎
- 简略的路由,/studens 渲染动态页进去
- 路由设计
- 提取路由模块
- 因为接下来的一系列业务操作都须要解决文件数据,所以咱们须要封装 Student.js’
-
先写好 student.js 文件构造
- 查问所有学生列别哦的 API
- findById
- save
- updateById
- deleteById
-
实现具体性能
- 通过路由收到申请
-
承受申请中的参数(get,post)
- req.query
- req.body
- 调用数据操作 API 解决数据
- 依据操作后果给客户端发送申请
-
业务性能程序
- 列表
- 增加
- 编辑
- 删除
子模板和模板的继承(模板引擎高级语法)【include,extend,block】
留神:
模板页:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title> 模板页 </title>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css"/>
{{block 'head'}}{{/block}}
</head>
<body>
<!-- 通过 include 导入公共局部 -->
{{include './header.html'}}
<!-- 留一个地位 让别的内容去填充 -->
{{block 'content'}}
<h1> 默认内容 </h1>
{{/block}}
<!-- 通过 include 导入公共局部 -->
{{include './footer.html'}}
<!-- 公共款式 -->
<script src="/node_modules/jquery/dist/jquery.js" ></script>
<script src="/node_modules/bootstrap/dist/js/bootstrap.js" ></script>
{{block 'script'}}{{/block}}
</body>
</html>
模板的继承:
header 页面:
<div id="">
<h1> 公共的头部 </h1>
</div>
footer 页面:
<div id="">
<h1> 公共的底部 </h1>
</div>
模板页的应用:
<!-- 继承 (extend: 延长,扩大) 模板也 layout.html -->
<!-- 把 layout.html 页面的内容都拿进来作为 index.html 页面的内容 -->
{{extend './layout.html'}}
<!-- 向模板页面填充新的数据 -->
<!-- 填充后就会替换掉 layout 页面 content 中的数据 -->
<!-- style 款式方面的内容 -->
{{block 'head'}}
<style type="text/css">
body{background-color: skyblue;}
</style>
{{/block}}
{{block 'content'}}
<div id="">
<h1>Index 页面的内容 </h1>
</div>
{{/block}}
<!-- js 局部的内容 -->
{{block 'script'}}
<script type="text/javascript">
</script>
{{/block}}
最终的显示成果:
[![image-20200316134759517]()](https://github.com/smallC-L-Y… 学习笔记.md)
MongoDB
关系型和非关系型数据库
关系型数据库(表就是关系,或者说表与表之间存在关系)。
- 所有的关系型数据库都须要通过
sql
语言来操作 - 所有的关系型数据库在操作之前都须要设计表构造
-
而且数据表还反对束缚
- 惟一的
- 主键
- 默认值
- 非空
非关系型数据库
- 非关系型数据库十分的灵便
- 有的关系型数据库就是 key-value 对儿
-
但 MongDB 是长得最像关系型数据库的非关系型数据库
- 数据库 -》数据库
- 数据表 -》汇合(数组)
- 表记录 -》文档对象
一个数据库中能够有多个数据库,一个数据库中能够有多个汇合(数组),一个汇合中能够有多个文档(表记录)
{
qq:{
user:[{},{},{}...
]
}
}
- 也就是说你能够任意的往里面存数据,没有结构性这么一说
装置
-
下载
- 下载地址:https://www.mongodb.com/downl…
-
装置
npm i mongoose
- 配置环境变量
- 最初输出
mongod --version
测试是否装置胜利
启动和敞开数据库
启动:
# mongodb 默认应用执行 mongod 命令所处盼复根目录下的 /data/db 作为本人的数据存储目录
# 所以在第一次执行该命令之前先本人手动新建一个 /data/db
mongod
如果想要批改默认的数据存储目录,能够:
mongod --dbpath = 数据存储目录门路
进行:
在开启服务的控制台,间接 Ctrl+C;
或者间接敞开开启服务的控制台。
[![image-20200314101047100]()](https://github.com/smallC-L-Y… 学习笔记.md)
连贯数据库
连贯:
# 该命令默认连贯本机的 MongoDB 服务
mongo
退出:
# 在连贯状态输出 exit 退出连贯
exit
[![image-20200314100821112]()](https://github.com/smallC-L-Y… 学习笔记.md)
根本命令
-
show dbs
- 查看数据库列表(数据库中的所有数据库)
-
db
- 查看以后连贯的数据库
-
use 数据库名称
- 切换到指定的数据库,(如果没有会新建)
-
show collections
- 查看当前目录下的所有数据表
-
db. 表名.find()
- 查看表中的详细信息
在 Node 中如何操作 MongoDB 数据库
应用官网的
MongoDB
包来操作http://mongodb.github.io/node…
应用第三方包
mongoose
来操作 MongoDB 数据库第三方包:
mongoose
基于 MongoDB 官网的mongodb
包再一次做了封装,名字叫mongoose
,是 WordPress 我的项目团队开发的。https://mongoosejs.com/
[![image-20200314105632745]()](https://github.com/smallC-L-Y… 学习笔记.md)
[![image-20200314105717993]()](https://github.com/smallC-L-Y… 学习笔记.md)
学习指南(步骤)
官网学习文档:https://mongoosejs.com/docs/i…
设计 Scheme 公布 Model (创立表)
// 1. 引包 // 留神:依照后能力 require 应用 var mongoose = require('mongoose');
// 拿到 schema 图表
var Schema = mongoose.Schema;
// 2. 连贯数据库
// 指定连贯数据库后不须要存在,当你插入第一条数据库后会主动创立数据库
mongoose.connect(‘mongodb://localhost/test’);
// 3. 设计汇合构造(表构造)
// 用户表
var userSchema = new Schema({
username: { // 姓名
type: String,
require: true // 增加束缚,保证数据的完整性,让数据按规矩对立
},
password: {
type: String,
require: true
},
email: {type: String}
});
// 4. 将文档构造公布为模型
// mongoose.model 办法就是用来将一个架构公布为 model
// 第一个参数:传入一个大写名词复数字符串用来示意你的数据库的名称
// mongoose 会主动将大写名词的字符串生成 小写复数 的汇合名称
// 例如 这里会变成 users 汇合名称
// 第二个参数:架构
// 返回值:模型构造函数
var User = mongoose.model(‘User’, userSchema);
### 增加数据(增)
// 5. 通过模型构造函数对 User 中的数据进行操作
var user = new User({
username: 'admin',
password: '123456',
email: 'xiaochen@qq.com'
});
user.save(function(err, ret) {
if (err) {console.log('保留失败');
} else {console.log('保留胜利');
console.log(ret);
}
});
### 删除(删)依据条件删除所有:
User.remove({
username: 'xiaoxiao'
}, function(err, ret) {
if (err) {console.log('删除失败');
} else {console.log('删除胜利');
console.log(ret);
}
});
依据条件删除一个:
Model.findOneAndRemove(conditions,[options],[callback]);
依据 id 删除一个:
User.findByIdAndRemove(id,[options],[callback]);
### 更新(改)更新所有:
User.remove(conditions,doc,[options],[callback]);
依据指定条件更新一个:
User.FindOneAndUpdate([conditions],[update],[options],[callback]);
依据 id 更新一个:
// 更新 依据 id 来批改表数据
User.findByIdAndUpdate(‘5e6c5264fada77438c45dfcd’, {
username: 'junjun'
}, function(err, ret) {
if (err) {console.log('更新失败');
} else {console.log('更新胜利');
}
});
### 查问(查)查问所有:
// 查问所有
User.find(function(err,ret){
if(err){console.log('查问失败');
}else{console.log(ret);
}
});
条件查问所有:
// 依据条件查问
User.find({username:’xiaoxiao’},function(err,ret){
if(err){console.log('查问失败');
}else{console.log(ret);
}
});
条件查问单个:
// 依照条件查问单个,查问进去的数据是一个对象({})
// 没有条件查问应用 findOne 办法,查问的是表中的第一条数据
User.findOne({
username: 'xiaoxiao'
}, function(err, ret) {
if (err) {console.log('查问失败');
} else {console.log(ret);
}
});
# 应用 Node 操作 MySQL 数据库
文档:https://www.npmjs.com/package/mysql
装置:
npm install –save mysql
// 引入 mysql 包
var mysql = require(‘mysql’);
// 创立连贯
var connection = mysql.createConnection({
host : ‘localhost’, // 本机
user : ‘me’, // 账号 root
password : ‘secret’, // 明码 12345
database : ‘my_db’ // 数据库名
});
// 连贯数据库(关上冰箱门)
connection.connect();
// 执行数据操作(把大象放到冰箱)
connection.query(‘SELECT * FROM users
‘, function (error, results, fields) {
if (error) throw error;// 抛出异样阻止代码往下执行
// 没有异样打印输出后果
console.log(‘The solution is: ‘,results);
});
// 敞开连贯(敞开冰箱门)
connection.end();
# 异步编程
## 回调函数
不成立的状况下:
function add(x,y){
console.log(1);
setTimeout(function(){console.log(2);
var ret = x + y;
return ret;
},1000);
console.log(3);
// 到这里执行就完结了,不会 i 等到后面的定时器,所以间接返回了默认值 undefined
}
console.log(add(2,2));
// 后果是 1 3 undefined 4
[![image-20200313085008929]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
应用回调函数解决:回调函数:通过一个函数,获取函数外部的操作。(依据输出失去输入后果)
var ret;
function add(x,y,callback){
// callback 就是回调函数
// var x = 10;
// var y = 20;
// var callback = function(ret){console.log(ret);}
console.log(1);
setTimeout(function(){
var ret = x + y;
callback(ret);
},1000);
console.log(3);
}
add(10,20,function(ret){
console.log(ret);
});
[![image-20200313084746701]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
留神:但凡须要失去一个函数外部异步操作的后果(setTimeout,readFile,writeFile,ajax,readdir)这种状况必须通过 回调函数 (异步 API 都会随同着一个回调函数)
ajax:
基于原生 XMLHttpRequest 封装 get 办法:
var oReq = new XMLHttpRequest();
// 当申请加载胜利要调用指定的函数
oReq.onload = function(){
console.log(oReq.responseText);
}
oReq.open(“GET”, “ 申请门路 ”,true);
oReq.send();
function get(url,callback){
var oReq = new XMLHttpRequest();
// 当申请加载胜利要调用指定的函数
oReq.onload = function(){//console.log(oReq.responseText);
callback(oReq.responseText);
}
oReq.open("GET", url,true);
oReq.send();
}
get(‘data.json’,function(data){
console.log(data);
});
## Promise
callback hell(回调天堂):
[![image-20200314143410972]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
文件的读取无奈判断执行程序(文件的执行程序是根据文件的大小来决定的)(异步 api 无奈保障文件的执行程序)
var fs = require(‘fs’);
fs.readFile(‘./data/a.text’,’utf8′,function(err,data){
if(err){
// 1 读取失败间接打印输出读取失败
return console.log('读取失败');
// 2 抛出异样
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
fs.readFile(‘./data/b.text’,’utf8′,function(err,data){
if(err){
// 1 读取失败间接打印输出读取失败
return console.log('读取失败');
// 2 抛出异样
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
通过回调嵌套的形式来保障程序:
var fs = require(‘fs’);
fs.readFile(‘./data/a.text’,’utf8′,function(err,data){
if(err){
// 1 读取失败间接打印输出读取失败
return console.log('读取失败');
// 2 抛出异样
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
fs.readFile('./data/b.text','utf8',function(err,data){if(err){
// 1 读取失败间接打印输出读取失败
return console.log('读取失败');
// 2 抛出异样
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
fs.readFile('./data/a.text','utf8',function(err,data){if(err){
// 1 读取失败间接打印输出读取失败
return console.log('读取失败');
// 2 抛出异样
// 阻止程序的执行
// 把错误信息打印到控制台
throw err;
}
console.log(data);
});
});
});
[![image-20200314144807008]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)为了解决以上编码方式带来的问题(回调天堂嵌套),所以在 EcmaScript6 新增了一个 API:`Promise`。[![image-20200314150050839]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
- Promise:承诺,保障
- Promise 自身不是异步的,但往往都是外部封装一个异步工作
根本语法:
// 在 EcmaScript 6 中新增了一个 API Promise
// Promise 是一个构造函数
var fs = require(‘fs’);
// 1 创立 Promise 容器 resolve: 解决 reject:失败
var p1 = new Promise(function(resolve, reject) {
fs.readFile('./a.text', 'utf8', function(err, data) {if (err) {// console.log(err);
// 把容器的 Pending 状态变为 rejected
reject(err);
} else {// console.log(data);
// 把容器的 Pending 状态变为 resolve
resolve(1234);
}
});
});
// 当 p1 胜利了,而后就(then)做指定的操作
// then 办法接管的 function 就是容器中的 resolve 函数
p1
.then(function(data) {console.log(data);
}, function(err) {console.log('读取文件失败了', err);
});
[![image-20200315100611620]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
链式循环:[![image-20200315125559136]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
封装 Promise 的 `readFile`:
var fs = require(‘fs’);
function pReadFile(filePath) {
return new Promise(function(resolve, reject) {fs.readFile(filePath, 'utf8', function(err, data) {if (err) {reject(err);
} else {resolve(data);
}
});
});
}
pReadFile(‘./a.txt’)
.then(function(data) {console.log(data);
return pReadFile('./b.txt');
})
.then(function(data) {console.log(data);
return pReadFile('./a.txt');
})
.then(function(data) {console.log(data);
})
mongoose 所有的 API 都反对 Promise:
// 查问所有
User.find()
.then(function(data){console.log(data)
})
注册:
User.findOne({username:’admin’},function(user){
if(user){console.log('用户已存在')
} else {
new User({
username:'aaa',
password:'123',
email:'fffff'
}).save(function(){console.log('注册胜利');
})
}
})
User.findOne({
username:'admin'
})
.then(function(user){if(user){
// 用户曾经存在不能注册
console.log('用户已存在');
}
else{
// 用户不存在能够注册
return new User({
username:'aaa',
password:'123',
email:'fffff'
}).save();}
})
.then(funciton(ret){console.log('注册胜利');
})
## Generator
async 函数
# 其余
## 批改完代码主动重启
咱们在这里能够应用一个第三方命名行工具:`nodemon` 来帮忙咱们解决频繁批改代码重启服务器的问题。`nodemon` 是一个基于 Node.js 开发的一个第三方命令行工具,咱们应用的时候须要独立装置:
在任意目录执行该命令都能够
也就是说,所有须要 –global 装置的包都能够在任意目录执行
npm install –global nodemon
npm install -g nodemon
如果装置不胜利的话,能够应用 cnpm 装置
cnpm install -g nodemon
装置结束之后应用:
node app.js
应用 nodemon
nodemon app.js
只有是通过 `nodemon` 启动的服务,则他会监督你的文件变动,当文件发生变化的时候,会主动帮你重启服务器。## 封装异步 API
回调函数:获取异步操作的后果
function fn(callback){
// var callback = funtion(data){console.log(data); }
setTimeout(function(){
var data = 'hello';
callback(data);
},1000);
}
// 如果须要获取一个函数中异步操作的后果,则必须通过回调函数的形式来获取
fn(function(data){
console.log(data);
})
## 数组的遍历办法,都是对函数作为一种参数
[![image-20200314094620191]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
## EcmaScript 6
> 参考文档:https://es6.ruanyifeng.com/
# 我的项目案例
## 目录构造
.
app.js 我的项目的入口文件
controllers
models 存储应用 mongoose 设计的数据模型
node_modules 第三方包
package.json 包形容文件
package-lock.json 第三方包版本锁定文件(npm5 之后才有)
public 公共动态资源
routes
views 存储视图目录
## 模板页
- 子模板
- 模板继承
## 路由设计
| 路由 | 办法 | get 参数 | post 参数 | 是否须要登录 | 备注 |
| --------------- | ---- | ------- | ----------------------- | ------------ | ------------ |
| / | get | | | | 渲染首页 |
| /register(登录) | get | | | | 渲染注册页面 |
| /register | post | | email,nickname,password | | 解决注册申请 |
| /login | get | | | | 渲染登陆界面 |
| /login | post | | email,password | | 解决登录申请 |
| /loginout | get | | | | 解决退出申请 |
| | | | | | |
## 模型设计
## 性能实现
## 步骤
- 创立目录构造
- 整合动态也 - 模板页
- include
- block
- extend
- 设计用户登陆,退出,注册的路由
- 用户注册
- 先解决客户端页面的内容(表单控件的 name,收集表单数据,发动申请)- 服务端
- 获取从客户端收到的数据
- 操作数据库
- 如果有错,发送 500 通知客户端服务器错了‘- 其余的依据业务发送不同的响应数据
- 登录
- 退出
# Express 中间件
## 中间件的概念
> 参考文档:http://expressjs.com/en/guide/using-middleware.html
[![image-20200316202757617]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
中间件:把很简单的事件宰割成单个,而后顺次有条理的执行。就是一个两头解决环节,有输出,有输入。说的通俗易懂点儿,中间件就是一个(从申请到响应调用的办法)办法。把数据从申请到响应分步骤来解决,每一个步骤都是一个两头解决环节。
var http = require(‘http’);
var url = require(‘url’);
var cookie = require(‘./expressPtoject/cookie’);
var query = require(‘./expressPtoject/query’);
var postBody = require(‘./expressPtoject/post-body’);
var server = http.createServer(function(){
// 解析申请地址中的 get 参数
// var obj = url.parse(req.url,true);
// req.query = obj.query;
query(req,res); // 中间件
// 解析申请地址中的 post 参数
req.body = {foo:'bar'}
});
if(req.url === ‘xxx’){
// 解决申请
...
}
server.listen(3000,function(){
console.log('3000 runing...');
});
同一个申请对象所通过的中间件都是同一个申请对象和响应对象。
var express = require(‘express’);
var app = express();
app.get(‘/abc’,function(req,res,next){
// 同一个申请的 req 和 res 是一样的,// 能够后面存储上面调用
console.log('/abc');
// req.foo = 'bar';
req.body = {
name:'xiaoxiao',
age:18
}
next();
});
app.get(‘/abc’,function(req,res,next){
// console.log(req.foo);
console.log(req.body);
console.log('/abc');
});
app.listen(3000, function() {
console.log('app is running at port 3000.');
});
[![image-20200317110520098]()](https://github.com/smallC-L-Y/Demo/blob/notes/nodeJS 学习笔记.md)
## 中间件的分类:
### 应用程序级别的中间件
万能匹配(不关怀任何申请门路和申请办法的中间件):
app.use(function(req,res,next){
console.log('Time',Date.now());
next();
});
关怀申请门路和申请办法的中间件:
app.use(‘/a’,function(req,res,next){
console.log('Time',Date.now());
next();
});
### 路由级别的中间件
严格匹配申请门路和申请办法的中间件
get:
app.get(‘/’,function(req,res){
res.send('get');
});
post:
app.post(‘/a’,function(req,res){
res.send('post');
});
put:
app.put(‘/user’,function(req,res){
res.send('put');
});
delete:
app.delete(‘/delete’,function(req,res){
res.send('delete');
});
### 总
var express = require(‘express’);
var app = express();
// 中间件:解决申请,实质就是个函数
// 在 express 中,对中间件有几种分类
// 1 不关怀任何申请门路和申请办法的中间件
// 也就是说任何申请都会进入这个中间件
// 中间件自身是一个办法,该办法接管三个参数
// Request 申请对象
// Response 响应对象
// next 下一个中间件
// // 全局匹配中间件
// app.use(function(req, res, next) {
// console.log(‘1’);
// // 当一个申请进入中间件后
// // 如果须要申请另外一个办法则须要应用 next()办法
// next();
// // next 是一个办法,用来调用下一个中间件
// // 留神:next()办法调用下一个办法的时候,也会匹配(不是调用紧挨着的哪一个)
// });
// app.use(function(req, res, next) {
// console.log(‘2’);
// });
// // 2 关怀申请门路的中间件
// // 以 /xxx 结尾的中间件
// app.use(‘/a’,function(req, res, next) {
// console.log(req.url);
// });
// 3 严格匹配申请办法和申请门路的中间件
app.get(‘/’,function(){
console.log('/');
});
app.post(‘/a’,function(){
console.log('/a');
});
app.listen(3000, function() {
console.log('app is running at port 3000.');
});
## 错误处理中间件
app.use(function(err,req,res,next){
console.error(err,stack);
res.status(500).send('Something broke');
});
配置应用 404 中间件:
app.use(function(req,res){
res.render('404.html');
});
配置全局错误处理中间件:
app.get(‘/a’, function(req, res, next) {
fs.readFile('.a/bc', funtion() {if (err) {// 当调用 next()传参后,则间接进入到全局错误处理中间件办法中
// 当产生全局谬误的时候,咱们能够调用 next 传递谬误对象
// 而后被全局错误处理中间件匹配到并进行解决
next(err);
}
})
});
// 全局错误处理中间件
app.use(function(err,req,res,next){
res.status(500).json({
err_code:500,
message:err.message
});
});
## 内置中间件
- express.static(提供动态文件)
- http://expressjs.com/en/starter/static-files.html#serving-static-files-in-express
## 第三方中间件
> 参考文档:http://expressjs.com/en/resources/middleware.html
- body-parser
- compression
- cookie-parser
- mogran
- response-time
- server-static