关于node.js:node

8次阅读

共计 30142 个字符,预计需要花费 76 分钟才能阅读完成。

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
  • 配置环境变量

解析执行 JavaScript

  1. 创立编写 JavaScript 脚本文件
  2. 关上终端,定位脚本文件的所属目录
  3. 输出 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')

服务端渲染以及客户端渲染

  1. 简略来说,在服务端应用模板引擎就是服务端渲染, 只须要申请一次。服务端会把 html 文件渲染好。所以速度更快.
  2. 客户端渲染

    浏览器申请,在服务端寄存的一个 html 文件。蕴含 ajax 以及模板渲染语法,浏览器申请后,失去服务器响应的字符串了。解析文件后。发现 script 以及 ajax 等 再次向服务器申请,失去服务器的响应数据后,最终应用模板引擎来替换显示在界面 ….. 问题是页面响应了,然而数据量大的话,可能会呈现白屏 …

    script link img iframe audio vedio 等具备外链的资源标签 src link 的 href 属性时浏览器会再次申请 a 链接的 href 属性不会立刻申请是须要点击的

  1. 分别渲染形式

    关上网页源代码,能够看到的就是服务端渲染的,客户端后续增加上的是没法看见的 …. 还有一个特色,会产生刷新 点击下一步后你会发现刷新这种的就是服务端渲染。前端个别是异步无刷新,只是部分更新

  2. 这里为什么须要两种 客户 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,能够用来 动静 获取以后文件的绝对路径(蕴含文件名)
  • __dirnamefilename 是不受执行 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
正文完
 0