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); //trueexports.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就会通过淘宝的服务器来下载jQuerycnpm 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 initThis 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 fieldsand exactly what they do.Use `npm install <pkg>` afterwards to install a package andsave 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中的模块零碎) clsversion: (1.0.0)description: 这是一个测试项目entry point: (main.js)test command:git repository:keywords:author: xiaochenlicense: (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)
// 引入expressvar express = require('express');// 1. 创立appvar 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'));// 引入expressvar express = require('express');// 创立appvar app = express();// 凋谢动态资源// 1.当以/public/结尾的时候,去./public/目录中找对应资源// 拜访:http://127.0.0.1:3000/public/login.htmlapp.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-templatenpm 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-urlencodedapp.use(bodyParser.urlencoded({ extended: false }))// parse application/jsonapp.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/dbmongod
如果想要批改默认的数据存储目录,能够:
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);
});
## Promisecallback 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('注册胜利');})
## Generatorasync函数# 其余## 批改完代码主动重启咱们在这里能够应用一个第三方命名行工具:`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