0%

NodeJs基础知识点

1.nodejs 的特点

1)单线程

在 Java、PHP 等服务器语言中,会为每一个客户端创建一个新的线程,而每个线程需要消耗大约 2MB 的内存。也就是说,一个 8GB 的内存可以满足 4000 人

的访问连接,这样就增加了服务器的硬件成本。Nodejs 不需要为每个用户的连接创建一个新的线程,而仅仅使用一个线程,一个 8GB 的内存可以满足
40000 人的连接。

  • 好处:操作系统不会再有创建线程、销毁线程的开销。
  • 坏处:如果一个用户导致了线程的奔溃,那么整个服务就奔溃了。

2)非阻塞 I/O

由于 Nodejs 采用了非阻塞 I/O 机制,因此在执行访问数据库的代码后,立即转而执行其后的代码,把数据库返回结果的代码处理放在了回调函数中,从而提高了
程序的执行效率。

当某个 I/O 执行完毕时,将以事件的形式通知执行 I/O 的线程,线程执行这个事件的回调函数,为了处理这个异步 I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。

3)事件驱动

在 nodejs 中,客户端请求建立连接,数据提交等行为,会触发相应的事件。在 nodejs 中,在一个时刻只能执行一个事件的回调函数,但是在执行一个事件回调函数
的中途,可以转而处理其他事件,然后返回继续执行原事件的回调函数,这种处理机制,称为‘事件环’机制。

2.nodejs 适合开发什么样的业务?

1
2
3
4
当应用程序需要处理大量并发的I/O,而在向客户端响应之前,应用程序内部不需要进行非常复杂处理的时候,nodejs非常合适。nodejs也非常适合与websocket
配合,开发长连接的实时交互应用程序。
总之,nodejs擅长任务的调度,善于I/O,不善于计算。
比如:1)用户表单收集 2)考试系统 3)聊天室 4)图文直播 5)提供JSON的api

3.第一个简单的 node 程序

1
2
3
4
5
6
7
8
9
10
let http = require('http');
// 创建服务器,参数是一个回调函数,表示如果有请求进来要做什么
let server = http.createServer((req,res)=>{
// 设置http头部,状态码是200,文件类型是html,字符集是utf8
res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});
res.end('这是我的第一个Node页面');
})

// 运行服务器
server.listen(3000,'192.168.124.15')

问:如何将 html 页面展示到浏览器中呢

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
利用引入fs模块
let http = require('http');
let fs = require('fs');
let path = require('path');
let PULIC_PATH = path.resolve(__dirname,'01_helloWorld.html');

// 创建服务器,参数是一个回调函数,表示如果有请求进来要做什么
let server = http.createServer((req,res)=>{
fs.readFile(PULIC_PATH,(err,data)=>{
console.log('data',data,err);
// 设置http头部,状态码是200,文件类型是html,字符集是utf8
res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});
res.end(data);
});
})

// 运行服务器
server.listen(3000,'192.168.1.9')

问:如何根据不同的路由展示不同的页面?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let http = require('http');
let fs = require('fs');
let PUBILC_PATH = require('path');

// 创建服务器,参数是一个回调函数,表示如果有请求进来要做什么
let server = http.createServer((req,res)=>{
if (req.url == '/sqaure') {
let path = PUBILC_PATH.resolve(__dirname,'01_helloWorld.html');
fs.readFile(path,(err,data)=>{
console.log('data',data,err);
// 设置http头部,状态码是200,文件类型是html,字符集是utf8
res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});
res.end(data);
});
} else if (req.url == '/circle') {
let path = PUBILC_PATH.resolve(__dirname,'01_helloWorld_circle.html');
fs.readFile(path,(err,data)=>{
console.log('data',data,err);
// 设置http头部,状态码是200,文件类型是html,字符集是utf8
res.writeHead(200,{"Content-type":"text/html;charset=UTF-8"});
res.end(data);
});
} else {
res.writeHead(404,{"Content-type":"text/html;charset=UTF-8"});
res.end('没有这个页面哦');
}

})

// 运行服务器
server.listen(3000,'192.168.1.9')

说明:在浏览器中输入http://192.168.1.9:3000/circle即可

4.http 模块与 url 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
实例:
let http = require('http');
let url = require('url');

let server = http.createServer((req,res)=>{
let path = url.parse(req.url);
/*
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?name=wq&age=20',
query: 'name=wq&age=20',
pathname: '/user',
path: '/user?name=wq&age=20',
href: '/user?name=wq&age=20'
}
*/
console.log('服务器接收到了请求1:',path);

// 将第二个参数设为true,就把query参数变为Object
let path2 = url.parse(req.url,true);
/*
Url {
protocol: null,
slashes: null,
auth: null,
host: null,
port: null,
hostname: null,
hash: null,
search: '?name=wq&age=20',
query: [Object: null prototype] { name: 'wq', age: '20' },
pathname: '/user',
path: '/user?name=wq&age=20',
href: '/user?name=wq&age=20'
}
*/
console.log('服务器接收到了请求2:',path2);

// 设置一个相应头
res.writeHead(200,{"Content-Type":"text/html;charset=UTF-8"});
// 每个请求都应该加上.end()方法,不然,浏览器请求会一直转菊花等待后端结束
res.end('<h1>响应头</h1>')
})

server.listen(3000,'192.168.1.9');

实操:做一个简单的表单提交

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<form action="http://192.168.1.9:3000" method="GET">
<input name='name' />
<input name='age' />
<input name='sex' />
<input type="submit">
</form>

let http = require('http');
let url = require('url');
let queryString = require('querystring');

let server = http.createServer((req,res)=>{
let queryObj = url.parse(req.url,true).query;
// querystring的作用与上句作用一样
let queryObj2 = queryString.parse(req.url.split('?')[1]);
console.log('参数',queryObj,queryObj2);

res.end('服务器收到了参数');
})

server.listen(3000,'192.168.1.9');

5.fs 模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
let http = require('http');
let fs = require('fs');

let server = http.createServer((req,res)=>{

let userID = parseInt(Math.random()*89999)+10000;
console.log(userID+'进入连接...')

res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8','Access-Control-Allow-Origin':'*'});

// 读取文件
fs.readFile('../笔记.txt',(error,data)=>{
console.log(error,data);
if (error) {
throw error;
}
console.log(userID+'读取完毕...')
res.end();
})

// 创建文件夹
fs.mkdir(`./image/${userID}`);

// 读取文件状态
fs.stat('../笔记.txt',(error,stats)=>{
/*
Stats {
dev: 580307240,
mode: 33206,
nlink: 1,
uid: 0,
gid: 0,
rdev: 0,
blksize: 4096,
ino: 10696049115206348,
size: 7275, // 文件的大小(以字节为单位)
blocks: 16,
atimeMs: 1579832397095.3948, // 表明上次访问此文件的时间戳
mtimeMs: 1579872595571.8716, // 表明上次修改此文件的时间戳
ctimeMs: 1579872595571.8716, // 表明上次更改文件状态的时间戳
birthtimeMs: 1579832397095.3948, // 表明此文件的创建时间的时间戳
atime: 2020-01-24T02:19:57.095Z,
mtime: 2020-01-24T13:29:55.572Z,
ctime: 2020-01-24T13:29:55.572Z,
birthtime: 2020-01-24T02:19:57.095Z
}
*/
console.log('读取文件状态',stats);
console.log('是否是文件夹:',stats.isDirectory());
console.log('是否是文件:',stats.isFile());
res.end();
})

// 存储所有文件夹名
let dictionary = [];
// 查看文件夹中有多少文件
fs.readdir('../node',(error,files)=>{
// 以数组的形式输出node文件夹中所有的文件名
/*
[
'01_helloWorld.html',
'01_helloWorld.js',
'01_helloWorld_circle.html',
'02_helloWorld.js',
'02_表单提交.html',
'03_router.js',
'04_EventLoop.js'
]
*/
console.log('node文件夹下的文件名:',files);
files.map(item => {
fs.stat(`./${item}`,(error,stats)=>{
if (stats.isDirectory()) {
dictionary.push(item);
}
console.log('文件夹:'+dictionary);
})
})
res.end();
})
})

server.listen(3000,'192.168.1.9');

// 实例:获取某个文件夹中所有文件(夹)的名字
let http = require('http');

let fs = require('fs');

let server = http.createServer((req,res)=>{
fs.readdir('../node',(error,files)=>{
// 存放文件夹的数组
let dictionary = [];
(function iterator(i){
if (i == files.length) {
res.end('获取目录结束...');
return;
}
fs.stat(`../node/${files[i]}`,(err,stats)=>{
if (stats.isDirectory()) {
dictionary.push(files[i]);
console.log('dictionary',dictionary)
}
iterator(i+1);
})
})(0)
})
})

server.listen(3000,'192.168.1.9');

6.制作一个静态资源文件管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 意思是:新建一个static文件夹,文件夹下有1.html文件,可以通过http://192.168.1.9:3000/1.html去访问
let http = require('http');
let url = require('url');
let fs = require('fs');
let path = require('path');

let server = http.createServer((req,res)=>{
// 获取路径
let pathName = url.parse(req.url).pathname;
if (pathName == '/') {
pathName = 'index.html';
}
// 获取文件拓展名
let extname = path.extname(pathName);
console.log('获取文件拓展名',extname);

// 获取文件
fs.readFile('./static/'+pathName,(error,data)=>{
if (error) {
fs.readFile('./static/404.html',(err,errData)=>{
console.log('errrr',err,errData)
res.writeHead(404,{'Content-Type':'text/html;charset=UTF8'});
res.end(errData);
})
return;
}
res.writeHead(200,{"Content-Type":getMIME(extname)})
res.end(data);
})
})

server.listen(3000,'192.168.1.9');

function getMIME(extname){
switch(extname){
case ".html":
return "text/html";
break;
case ".jpg":
return "image/jpg";
break;
case ".css":
return "text/css";
break;
}
}

7.文件夹模块和 package 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1)在js文件中引用,如果不写./ , 会默认查找node_modules文件夹下的文件

test.js文件
let foo = require('foo.js');
console.log(foo);

node_modules文件夹下foo.js文件
let a = 200;
exports.b = b;

2)在js文件中,如果引用不加扩展名,默认引用文件夹下index.js文件

test.js文件
let a = 'bar';
exports.a = a;

node_modules文件夹下bar文件夹下的index.js文件
let a = 'bar';
exports.a = a;

问:如果修改bar文件夹下index.js文件夹名为app.js,如何修改才能正常引用?
在bar文件夹下新建文件package.json,
package.json文件
{
"name": "app",
"version": "0.0.1",
"main": "app.js"
}

3)package.json管理依赖
在根文件夹下执行命令npm init,会生成package.json文件
package.json中:
"dependencies": {
"moment": "^2.24.0" // ^在谁前面就表示谁不变,在这里就表示2的大版本保持不变
},

4)路径注意问题
前提:同级目录下有a.js文件和text文件夹,text文件夹下有b.js和c.js
引用:
1.a引用b
let b = require('./text/b.js);
2.b引用c
let c = require('./c.js);
注意:引用都是从当前文件寻找其他文件
问:如果b.js中需要引入像fs等第三方模块读取文件时,如何引用?
使用绝对路径__dirname:
fs.readFile(__dirname+'/1.txt',()=>{})

8.POST 请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
<input id='name' />
<input id='age' />
<input id='submit' type="submit" value="提交" />
<script>
document.getElementById('submit').onclick=()=>{
let name = document.getElementById('name').value;
let age = document.getElementById('age').value;

let xhr = new XMLHttpRequest();
xhr.open('POST','http://192.168.1.9:3000');
xhr.addEventListener('load',function(){
console.log(this.response);
})
let obj = {
name,
age
};
xhr.send(JSON.stringify(obj));
}
</script>


let http = require('http');
let server = http.createServer((req,res)=>{
if (req.method == "POST") {
let allData = '';
req.on('data',(chunk)=>{
allData += chunk;
})
req.on('end',()=>{
res.writeHead(200,{'Content-Type':'text/html','Access-Control-Allow-Origin':'*'});
res.end(allData);
})
}
})
server.listen(3000,'192.168.1.9');

例:实现上传图片
前提:npm install formidable

<form action="http://192.168.1.9:3000" method="POST" enctype="multipart/form-data">
<input type="text" name='descript' />
<input type="file" name="file" />
<input type="submit" value="提交" />
</form>

let http = require('http');
let formidable = require('formidable');
let fs = require('fs');
let path = require('path');
let server = http.createServer((req,res)=>{
if (req.method == "POST") {
let form = new formidable.IncomingForm();
// 设置文件上传存储地址
form.uploadDir = './upLoads';
// 所有的文本域、单选框等都存放在fields中;所有的文件域都存放在files中
form.parse(req,(err,fields,files)=>{
// 修改文件名
let oldPath = __dirname + "/" + files.file.path;
let newPath = __dirname + "/upLoads" + "/" + fields.descript + path.extname(files.file.name);
console.log('修改文件名',oldPath,newPath);
fs.rename(oldPath,newPath,(error)=>{
if (error) {
throw Error('改名失败!');
}
res.writeHead(200,{"Content-Type":"text/plain;charset=utf-8"});
res.end('上传成功');
})
})
}
})
server.listen(3000,'192.168.1.9');

9.模板引擎

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1)ejs模板引擎:是一种后端模板引擎

let ejs = require('ejs');

let str = '今天买了<%= a %>s';
let data = {
a:6,
}

let html = ejs.render(str,data)
console.log(html); // 今天买了6s

问:如何读取ejs页面?

index.ejs

<!DOCTYPE html>
<html lang="en">
<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>Document</title>
</head>
<body>
<h1>今天买了<%= a %>s</h1>
</body>
</html>

let ejs = require('ejs');
let fs = require('fs');
let http = require('http');

let server = http.createServer((req,res)=>{
fs.readFile("./views/ejs01.ejs",(err,data)=>{
let template = data.toString();
let obj = { a: 6};

let html = ejs.render(template,obj);

res.writeHead(200,{'Content-Type':'text/html;charset=utf-8','Access-Control-Allow-Origin':'*'});
res.end(html);
})
})
server.listen(8000,'127.0.0.1');

2)Jade模板引擎:也是一种后端模板引擎,省略了html标签

10.Express 框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
Express是后端Node的框架。
前提:npm install express
1)初识Express
let express = require('express');

let app = express();


// express路由能力
app.get("/index",(req,res)=>{
res.send('首页');
})

app.get("/my",(req,res)=>{
res.send('我的');
})

app.get(/\/student\/([\d]{5})/,(req,res)=>{
res.send("学生信息,学号:"+req.params[0]);
})

app.get("/teacher/:teacherID",(req,res)=>{
res.send("老师信息,工号:"+req.params.teacherID);
})

// express引用静态文件能力(即以前放入Apache中的包)
app.use(express.static('./static'));

// express引用模板引擎能力
app.set('view engine','ejs');
app.get('/view',(req,res)=>{
res.render('ejs01',{
a: 11,
})
})

app.listen(3000);

2)如果想要处理任何类型的请求(get,post)就使用app.all
app.all("/",(req,res)=>{

})

3)Restful路由设计:简单来说,就是同一个路由路径,根据不同的请求类型,展现出不同的功能

4)中间件
如果GET、POST请求的回调函数中,没有next参数,那么就会匹配第一个路由,不会继续往下匹配;如果想要继续往下匹配,就需要next()

let express = require('express');

let app = express();

app.get('/',(req,res,next)=>{
console.log('1');
next();
})

app.get('/',(req,res)=>{
console.log('2');
})

app.listen(3000);

1)app.use()是一个中间件,这与get/post不同的是,app.use()的网址不是精确匹配的,是可以扩展的
let express = require('express');

let app = express();

app.use("/admin",(req,res)=>{
// 当用户输入 http://127.0.0.1:3000/admin/userinfo/001
console.log(req.originalUrl); // 用户输入访问的网址 /admin/userinfo/001
console.log(req.baseUrl); // use中的第一个参数 /admin
console.log(req.path); // 用户网址减去use中的第一个参数 /userinfo/001
res.end();
})

app.listen(3000);

2)当app.use不写路径时,实际上是相当于"/",代表所有网址
app.use((req,res,next)=>{
next();
})

3)静态服务
let express = require('express');

let app = express();

// 当用户访问http://127.0.0.1:3000/static/即可访问static文件夹下文件
app.use('/static',express.static('./static'));

// use函数会自动识别err这个参数,如果有就能自动捕获
app.use((req, res)=>{
res.send('不存在这个页面!');
})

app.listen(3000);

4)render()和send()
①大多数情况下,渲染内容用res.render(),将会根据views中的模板文件进行渲染。如果渲染不想使用views文件夹,可以:
app.set('views',__dirname+'/Views2');
②如果想写一个快速测试页,当然可是使用res.render()。这个函数将根据内容,自动帮我们设置了Content-Type头部和200状态码
③如果想要使用不同的状态码,可以:
res.status(400).render('we connot find it')
④如果想要设置不同的Content-Type,可以:
res.set('Content-Type','text-html');

5)express的GET和POST请求
①GET请求
let express = require('express');

let app = express();

app.get('/',(req,res)=>{
// 获取参数
// 当访问http://127.0.0.1:3000/?name=wq&id=1270837469
console.log(req.query); // { name: 'wq', id: '1270837469' }
res.send();
})

app.listen(3000);
②POST请求

前提:npm install body-parser
let bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended:false}));
app.post('/',(req,res)=>{
res.send(JSON.stringify(req.body));
})

11.NoSQL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
定义:非结构性数据库,没有行和列的概念,用JSON来存储数据,代替了老牌数据库表和行的概念,分别使用集合和文档。

mongodb的一些命令:
mongo:使用数据库
mongod:开机
mongoimport:导入数据

启动mongodb:
新建一个文件夹我的目录是:F:\mongo
打开cmd,执行 mongod --dbpath F:\mongo
新打开一个cmd,执行 mongo

mongodb命令:
show dbs:展示当前所有数据库
use 数据库名:使用指定数据库;或者新建数据库
db:查看当前所在数据库
插入数据:
db.数据库名.insert({"name":"wq"})
查看当前数据库集合:
show collections
查看当前集合中的文档:
db.数据库名.find()
查询name字段为'wq'的文档:
db.数据库名.find({"name":"wq"})
删除数据库:(当前所在的数据库)
db.dropDatabase()
导入数据库:
mongoimport --db 数据库名 --collection 集合名 --drop --file 文件路径
注意: --drop 代表删除之前集合中存在的数据
查询:
数据结构:
{
"name":"wq",
"age":23,
"hobby":["sleep","eat"],
"score":{
"yuwen":89,
"shuxue":100
},
"points": [
{ "points": 78, "bonus": 8 },
{ "points": 57, "bonus": 7 }
]
}
1)查询数学成绩为100的学生
db.student.find({"score.shuxue":100})
2)查询年龄为23并且数学成绩为100的学生
db.student.find({"score.shuxue":100,"age":23})
3)查询语文成绩大于70分的学生($gt)
db.student.find({"score.yuwen":{$gt:70}})
4)查询语文成绩小于70分的学生($lt)
db.student.find({"score.yuwen":{$lt:70}})
4)查询语文成绩小于70或者年龄小于20岁的学生
db.student.find({$or:[{"score.yuwen":{$lt:70}},{"age":{$lt:20}}]})
5)查询年龄大于15岁的学生并且按照语文成绩升序排列(1代表升序,-1代表降序),如果有两个参数,则先按前者排序,后按后者排序
db.student.find({"age":{$gt:15}}).sort({"age":1})
6)查询爱好为睡觉的学生
db.student.find({"hobby":"sleep"})
7)查询第二个爱好为eat的学生
db.student.find({"hobby.1":"eat"})
8)查询bonus大于7的学生
db.student.find({"points":{$elemMatch:{"bonus":{$gt:7}}}})
9)查询hobby为eat和sleep的学生
db.student.find({"hobby":{$all:["eat","sleep"]}})
10)查询爱好为2个的学生
db.student.find({"hobby":{$size:2}})

删除
1)删除集合
db.集合名.drop()
2)删除集合中名字为wq的学生
db.student.remove({"name":"wq"})
注意:只删除一个添加{justOne:true}
db.student.remove({"name":"wq"},{justOne:true})
修改
1)修改名字为wq2的学生年龄为21
db.student.update({"name":"wq2"},{$set:{"age":21}})
2)修改名字满足wq\d{1,}所有学生的年龄为33
db.student.updateMany({"name":/wq\d{1,}/},{$set:{"age":33}})
3)完全替换名字为wq2
db.student.update({"name":"wq2"},{"name":"wq2","age":1})
4)添加points
db.students.update({"name":"wq"},{$addToSet:{"points":{ "points": 58, "bonus": 7 }}})

12.Nodejs 连接 Mongodb 数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
let express = require('express');

let app = express();

let MongoClient = require('mongodb').MongoClient;

app.get('/',(req,res)=>{
// itcase代表数据库
let url = "mongodb://127.0.0.1:27017/itcase";
MongoClient.connect(url,(err,client)=>{
if (err) {
console.log('数据库连接失败!')
return;
}
console.log('数据库连接成功!')
let db = client.db("itcase");
db.collection('student').insertOne({
"name":"wcc",
"age":30
},(error,result)=>{
if (error) {
console.log('数据插入失败!')
return;
}
console.log('result',result);
res.send();
})
})
})

app.listen(3000);

13.nodejs 操作 mongodb(增删改查)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
let MongoClient = require('mongodb').MongoClient;

// 连接数据库
function connectMongodb(dbName,callback){
let url = `mongodb://127.0.0.1:27017/${dbName}`;
MongoClient.connect(url,callback)
}

// 插入数据
exports.insertOne = (dbName,collectionName,data,callback) => {
connectMongodb(dbName,(err,client)=>{
if (err) {
console.log('数据库连接失败!')
return;
}
let db = client.db(dbName);
db.collection(collectionName).insertOne(data,callback);
})
}

// 查询数据
exports.find = (dbName,collectionName,condition,pageSize,pageNo,callback) =>{
connectMongodb(dbName,(err,client)=>{
let db = client.db(dbName);
let cursor = db.collection(collectionName).find(condition).limit(pageSize).skip((pageNo-1)*pageSize);
let result = [];
cursor.each((error,doc)=>{
if (doc!=null) {
result.push(doc);
}else {
callback(null,result);
}
})
})
}

// 删除数据
exports.delete = (dbName,collectionName,condition,callback)=>{
connectMongodb(dbName,(err,client)=>{
let db = client.db(dbName);
db.collection(collectionName).deleteMany(condition,(error,result)=>{
if(error){
callback('删除失败!',null);
return;
}
callback(null,result);
})
})
}

// 修改数据
exports.update = (dbName,collectionName,searchCondition,updateData,callback)=>{
connectMongodb(dbName,(err,client)=>{
let db = client.db(dbName);
db.collection(collectionName).updateOne(searchCondition,{$set:updateData},(error,result)=>{
if(error){
callback('修改失败!',null);
return;
}
callback(null,result);
})
})
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Cookie:
1)Http是无状态协议,简单的说,当你浏览一个页面,然后转到同一个网站的另一个页面,服务器无法认识到这是同一个浏览器在访问同一个网站。每一次访问都是没有关系的。
2)Cookie是一个简单到爆的想法:当访问一个页面的时候,服务器在下行Http报文中,命令浏览器存储一个字符串;当浏览器再次访问同一个域的时候,将把这个字符串携带到
上行Http请求中。
特点:
1)Cookie不加密,用户可以自由看到
2)用户可以删除Cookie或者禁用它
3)Cookie可以被篡改
4)Cookie可以用于攻击
5)Cookie的存储量小

node中的Cookie:
前提:npm install cookie-parser
例子:
let express = require('express');
let cookieParser = require('cookie-parser');
let app = express();
app.use(cookieParser());

app.get('/',(req,res)=>{
console.log('请求Cookie',req.cookies)
// maxAge:Cookie的有效期
res.cookie('name','wq',{maxAge:24*60*60*1000});
res.send();
})
app.listen(3000);

Session:
Session不是一开始就有的技术,而是依赖Cookie。当浏览器禁用cookie或者用户清除cookie的时候登录效果就消失了。
Session下发的乱码是乱码,并且服务器自己缓存一些东西,下次服务器带着乱码请求,与缓存比对,就知道请求用户是谁了。

node中的Session:
前提:npm install express-session
let express = require('express');
let app = express();

let session = require('express-session');

app.use(session({
secret:'wq',
resave:false,
saveUninitialized:true
}))

app.get('/',(req,res)=>{
if (req.session.userInfo) {
res.send('欢迎您,'+req.session.userInfo);
return;
}
res.send('您未登录,请先登录!!')
})

app.get('/login',(req,res)=>{
req.session.userInfo = '王清'; // 设置Session
res.send('您已成功登录!');
})

app.listen(3000);

14.MD5 加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    MD5加密是函数型加密,就是每次加密的结果是一样的,没有随机位。
特点:
1)无论需要加密的文字多长多短,永远是32位。
2)哪怕只改一个字,密文都会大变。

node中的加密:
前提:npm install crypto
let express = require('express');
let app = express();
let crypto = require('crypto');

app.get('/',(req,res)=>{
// 选择加密方式,一般有:sha1,md5,sha256,sha512
let md5 = crypto.createHash('md5');
let password = md5.update('wq').digest('base64');
res.send("加密之后的密码:"+password);
})

app.listen(3000);

16.Mongoose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
简介:是一个将JavaScript对象与数据库产生联系的框架。Object Related Model(ORM:对象关系模型)。操作对象就是操作数据库
前提:npm install mongoose
例子demo:
let mongoose = require('mongoose');
// 连接数据库
mongoose.connect('mongodb://127.0.0.1/animals');

// 创建模型:相当于创建了一个类,每个Cat实例都有name和age属性,在mongo中相当于文档
let Cat = mongoose.model('cat',{name:String,age:Number});

// 实例化
let Ketty = new Cat({name:'Ketty',age:12});

// 保存到数据库
Ketty.save((err,result)=>{
console.log(err,result);
})
封装增删改查:
前提:在同一目录下新建models文件夹和app.js文件,models文件夹下新建db.js和student.js;
代码:
app.js:
let db = require('./models/db');

let Student = require('./models/student');

// 添加方法一:
let xiaoming = new Student({name:'小明',age:18})
xiaoming.save(()=>{console.log('添加小明成功!')})

// 添加方法二:
Student.create({name:'小红',age:20,sex:'女'},()=>{console.log('添加小红成功!')});

// 查找方法一:利用自定义的静态方法查找
Student.findByName('小红',(err,result)=>{console.log(result)})

// 查找方法二:
Student.find({name:'小红'},(err,result)=>{console.log(result)});

// 修改小红年龄为30岁:这里可以不用添加$set为{$set:{age:30}}
Student.updateOne({name:'小红'},{age:30},(err,result)=>{console.log(result)})

// 修改方法二:
Student.find({name:'小红'},(err,result)=>{
let xiaohong = result[0];
xiaohong.age=30;
xiaohong.save();
});

// 删除小红
Student.deleteOne({name:'小红'},(err,result)=>{console.log(result)})

// 使用实例方法
let xiaoqiang = new Student({name:'小强',age:22});
xiaoqiang.console();
db.js:
let mongoose = require('mongoose');

// 创建连接,给每个用户都会创建一个连接
let db = mongoose.createConnection('mongodb://127.0.0.1:27017/school')

db.once('open',()=>{
console.log('数据库连接成功!');
})

module.exports = db;
student.js:
let mongoose = require('mongoose');
let db = require('./db');

let studentSchema = new mongoose.Schema({
name : {type:String},
age : {type:Number},
sex : {type:String,default:'男'}
})

// 创建查询静态方法
studentSchema.statics.findByName = (name,callback) => {
db.model('student').find({name},callback);
}

/**
* 创建更改静态方法
* conditions:修改条件
* data:改成data
* options:可选参数,它有如下属性
* safe :(布尔型)安全模式(默认为架构中设置的值(true))
upsert :(boolean)如果不匹配,是否创建文档(false)
multi :(boolean)是否应该更新多个文档(false)
runValidators:如果为true,则在此命令上运行更新验证程序。更新验证器根据模型的模式验证更新操作。
strict:(布尔)覆盖strict此更新的选项
overwrite: (布尔)禁用只更新模式,允许您覆盖文档(false)
*/
studentSchema.statics.update = (conditions,data,options,callback) => {
db.model('student').update(conditions,{$set:data},options,callback);
}

// 定义实例方法
studentSchema.methods.console = ()=>{
console.log('这是实例方法')
}

let studentModel = db.model('student',studentSchema);

module.exports = studentModel;

17.WebSocket 和 Socket.IO 框架

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
WebSocket允许客户端和服务器以全双工的方式进行通信;WebSocket的原理:利用HTTP请求产生握手之后,二者转用TCP协议进行交流(QQ协议)

方法一:利用socket.io模块
前提:npm install socket.io
模拟websocket:
前端代码studyWebsocket.html:
<h1>模拟websocket</h1>
<input id='content' /><button id='send'>发送</button>
<script src="https://cdn.bootcss.com/socket.io/2.2.0/socket.io.dev.js"></script>
<script>
var socket = io.connect('http://127.0.0.1:3000');
document.getElementById('send').onclick = ()=>{
socket.emit('question',document.getElementById('content').value);
}
socket.on('answer',data=>console.log(data));
</script>
Node代码:
(
如果使用express框架:
const express = require('express');
const app = express();
let server = require('http').createServer(app);
let io = require('socket.io')(server);
)
let http = require('http');
let fs = require('fs');

let server = http.createServer((req,res)=>{
if (req.url == '/') {
fs.readFile('./studyWebsocket.html',(err,data)=>{
res.end(data);
})
}
})

let io = require('socket.io')(server);

// 监听连接事件
// 对于前端和后端的socket对象,都有emit和on方法,emit发送请求,on接受请求
io.on('connection',socket=>{
socket.on('question',data=>{
socket.emit('answer',data);
})
// 广播:所有连接到此websocket上来的用户,如果其中一个用户发起thank请求,所有用户都能得到回应
io.emit('broadcast',{'say':'谢谢'});
})

server.listen(3000,'127.0.0.1');

方法二:利用ws模块
前端代码:
<h1>模拟websocket</h1>
<input id='content' /><button id='send'>发送</button>
<script>
var ws = new WebSocket('ws://127.0.0.1:3000');
ws.addEventListener('open',()=>{
ws.send('连接成功...');
})
document.getElementById('send').onclick = ()=>{
// 给服务器发送一个字符串:
ws.send(document.getElementById('content').value);
}
ws.onmessage = result=>{
console.log(result.data);
}
</script>

node代码:
const WebSocket = require('ws');
// 实例化:
const wss = new WebSocket.Server({
port: 3000
});

// 监听连接事件
wss.on('connection',(ws)=>{
// 接受对方发送过来的信息
ws.on('message',data=>{
ws.send(data);
})
})