node学习笔记
node
首先,Node不为每个用户开辟一个线程,所以非常极端的选择了单线程。单线程,要照顾所有的用户,那么就必须有非阻塞I/O,否则一个人的I/O就把别人、自己都阻塞了。一旦有非阻塞I/O,一个人如果I/O去了,就会放弃CPU的使用权,换成另一个人使用CPU(或者执行此人后面的语句)。所以CPU的利用率100%。第一个人I/O结束了,就要用事件来通知线程,执行回调函数。此时必须有事件环,就有一个排队调度机制。Node中有超过半数的C++代码,在搭建事件环。
Node.js和别的老牌3P不一样:
- 没有自己的语法,使用V8引擎,所以就是JS。V8引擎解析JS的,效率非常高,并且V8中很多东西都是异步的。Node就是将V8中的一些功能自己没有重写(别人做了,自己就站在巨人肩膀上),移植到了服务器上。
- 没有web容器,就是安装配置完成之后,没有一个根目录。
http–协议
request 请求<–输入的信息
response 响应–>输出给浏览器信息
fs模块–File Systerm文件系统
fs
异步vs同步
- 异步–多个操作同时进行,前一个操作没完成,后面的也能开始
- 同步–一次一个
fs.readFile(文件名, (错误err, 文件内容) => {})
writeFile(文件名,内容,(err)=>{})
数据请求
前台数据请求—form ajax jsonp
后台->一样,只是接受了http请求
前后台只通过http协议传输
请求方式:
- GET 数据在url中一起传输
- POST 数据不在url里,post数据比get数据大的多
req.url ==> /aaa?user=123123123&pass=123123123123
GET数据解析
自己动手split
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const http = require('http');
var server = http.createServer(function (req, res) {
var GET = {};
if (req.url.indexOf('?')>-1) {
var arr1 = req.url.split('?');
var arr2 = arr1[1].split('&');
for (var i = 0; i < arr2.length; i++) {
var arr3 = arr2[i].split('=');
GET[arr3[0]] = arr3[1];
}
}
console.log(req.url, GET);
res.write('123');
res.end();
}).listen(8080);querystring
1
2
3
4
5
6
7
8
9
10const http = require('http');
const querystring = require('querystring');
var server = http.createServer(function (req, res) {
var GET = querystring.parse(req.url.split('?')[1]);
console.log(req.url, GET);
res.write('123');
res.end();
}).listen(8080);url
1
2
3
4
5
6
7
8
9
10const http = require('http');
const urllib = require('url');
var server = http.createServer(function (req, res) {
var GET = urllib.parse(req.url, true).query;
console.log(req.url, GET);
res.write('123');
res.end();
}).listen(8080);
POST数据解析
1 | //data有一段数据到达(发生很多次) |
综合
1 | const http=require('http'); |
案例:登陆注册页
访问类型分两类
- 对文件的访问
http://localhost:8080/1.html
- 对接口的访问
http://localhost:8080/user?act=login
server.js
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
64const http = require('http');
const fs = require('fs');
const querystring = require('querystring');
const urllib = require('url');
var users = {};//{用户名1:密码1,用户名2:密码2,用户名3:密码3,}
http.createServer(function (req, res) {
//解析数据
var str = '';
req.on('data', function (data) {
str += data;
});
req.on('end', function (data) {
var obj = urllib.parse(req.url, true);
const url = obj.pathname;
const GET = obj.query;
const POST = querystring.parse(str);
if (url == '/user') {
switch (GET.act) {
case 'reg':
//1.检查用户是否存在
if (users[GET.user]) {
res.write('{ "ok": false, "msg": "此用户已存在"}');
} else {
//2.插入user
users[GET.user] = GET.pass;
res.write('{ "ok": true, "msg": "注册成功"}');
}
break;
case 'login':
//1.检查用户是否存在
if (users[GET.user] == null) {
res.write('{ "ok": false, "msg": "此用户不存在"}');
} else if (users[GET.user] != GET.pass) {
//2.检查用户密码
res.write('{ "ok": false, "msg": "用户名或密码有误"}');
} else {
res.write('{ "ok": true, "msg": "登陆成功"}');
}
break;
default:
res.write({
"ok": false,
"msg": '未知的act'
});
}
res.end();
} else {
//读取文件
var file_name = './www' + url;
fs.readFile(file_name, function (err, data) {
if (err) {
res.write('404');
} else {
res.write(data);
}
res.end();
});
}
});
}).listen(8080);user.html
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<script src="ajax.js"></script>
<script>
window.onload = function () {
var oTxtUser = document.getElementById('user');
var oTxtPass = document.getElementById('pass');
var oBtnReg = document.getElementById('reg_btn');
var oBtnLogin = document.getElementById('login_btn');
oBtnLogin.onclick = function () {
ajax({
url: 'user',
data: {act: 'login', user: oTxtUser.value, pass: oTxtPass.value},
type:'get',
success: function (str) {
console.log(str);
var json = eval('(' + str + ')');
if (json.ok) {
alert('登陆成功');
} else {
alert('登陆失败 :' + json.msg);
}
},
error: function () {
alert('通信失败')
}
});
};
oBtnReg.onclick = function () {
ajax({
url: '/user',
data: {act: 'reg', user: oTxtUser.value, pass: oTxtPass.value},
type: 'get',
success: function (str) {
var json = eval('(' + str + ')');
if (json.ok) {
alert('注册成功');
} else {
alert('注册失败' + json.msg);
}
},
error: function () {
alert('通信失败')
}
});
}
}
</script>
</head>
<body>
用户: <input type="text" id="user"><br>
密码: <input type="password" id="pass"><br>
<input type="button" value="注册" id="reg_btn"><input type="button" value="登陆" id="login_btn">
</body>
模块化
- 系统模块:http querystring url
自定义模块
- require 引入自定义模块时必须加
./
,可以不加.js
- exports 单个输出
- module.exports={};批量输出
- 自定义模块可以统一放入node_modules里面,可以不加
./
- require 引入自定义模块时必须加
包管理器
express
基本用法
1
2
3
4
5
6
7
8
9
10//1.创建服务
const express = require('express');
var server = express();
//3. 处理用户请求server.user('地址',function(req,res){})
server.use('/a.html', function (req, res) {
res.send('abc');
res.end();
});
//2.监听
server.listen(8080);
express保留了原生的功能,添加了一些方法(send),增强原有功能
- .get(‘/‘,function(req,res){});
- .post(‘/‘,function(req,res){});
- .use(‘/‘,function(req,res){});–get和post都可以
express案例
- 设计接口
请1求: /login?user=xxx&pass=xxx
返回: {ok:true/false,msg:’结果’}
1 | const express = require('express'); |
bodyParser
req.query–>GET 无需额外的中间键
req.body –>POST 需要body-parser,分两步,只能解析post数据,不能解析post文件1
2
3
4
5
6//要先用bodyParser解析,然后才能用,body来自bodyParser
server.use(bodyParser.urlencoded({}));
server.use('/', function (req, res) {
console.log(req.body);//post
});
//{ user: '1234', pass: '1234' }
bodyParser.urlencoded({})
有两个参数
- extended:true //扩展模式
- limit: 2*1024*1024
- bodyParser的实现原理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15const querystring = require('querystring');
module.exports = {
aaa: function () {
return function (req, res, next) {
var str = '';
req.on('data', function (data) {
str += data;
});
req.on('end', function () {
req.body = querystring.parse(str);
next();
});
}
}
};
链式操作
当server.use(‘/‘,function(req,res,next){
next();
})链式操作需要添加next
server.use(function(){})如果不加路径,无论是哪种路径请求都可以接受
cookie session
- cookie : 在浏览器保存一些数据,每次请求都会带回来,不安全,有限(4k)
- 读取
req.signedCookies
req.cookies
- 发送
- 指定路径:
res.cookie('user', 'yangze', {path: '/aaa', maxAge: 30 * 24 * 3600 * 1000});
- 加密:`req.secret = ‘sadfasdfwe’;
res.cookie('user', 'yang', {signed: true});`
- 删除cookie
res.clearCookie('user')
- 指定路径:
- 读取
1 | const express = require('express'); |
- session : 保存在服务端,安全性好,空间近乎无限,session基于cookie实现,不能独立存在,cookie中有一个session的id,服务器利用session id找到session的文件、读取、写入。。。有一个隐患:session劫持
cookie-session
1
2
3
4
5
6
7
8
9
10
11server.use(cookieParser());<br>
server.use(cookieSession({
name : 'sess',//给session起名字
keys : ['aaa','bbb','ccc'],
maxAge : 2 * 3600 * 1000
}));
server.use('/',function(req, res){
req.session
});
// 删除session
delete req.session
模板引擎
用来生成页面
- jade
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//1.根据缩进,规定层级
//2.属性放在()里面,逗号分隔
//3.内容,直接在后面空格然后添加
//4.style有两种写法,一种是普通属性写法,第二种是json格式写法
//5.class可以用数组形式写
//6.简写 div.box -- div#div1
//7.div&attributes({title:'aaa',id:'div1'})
//8.|为本,代表原样输出内容
//9. . 代表所有下一级的内容,全部原样输出
//10. script下使用include引入外部js文件
//11. div #{a+b}
//12.可以在renderFile里将style写成json格式,把class写成数组格式
//13.可以将自己的class融入到class的数组里
//14. 使用-var a=12;在jade中定义变量
//15. 在jade中, span #{a} ,span=a 都是输出renderFile里的数据
//16. 在jade中可以使用for,if,else,switch
//17. 可以使用!=,将标签<>直接写入html
html
head
style
script
include a.js
script.
window.onload = function () {
var oBtn = document.getElementById('btn1');
oBtn.onclick = function () {
alert('aaa');
};
};
script(src='a.js')
|window.onload=function(){
|var oBtn=document.getElementById('btn1');
|oBtn.onclick=funtion(){
| alert('aaa')
|};
link(href="a.css",ref="ref/stylesheet")
body
div(class=['aaa','left-warp','active'])
ul
li hello
li
li
div(style={width:'200px',height:'200px',background:'red'})
div&attributes({title:'aaa',id:'div1'})
div 我的名字: #{name}
div(style=json)
div(class=arr class="active")
div
-var a=12;
-var b=12;
div 结果是: #{a+b}
div
-for(var i=0;i<array.length;i++)
div=array[i]
div
div!=content
div=content
div
-var a=19;
-if (a%2==0)
div(style={background:'red'}) 偶数
-else
div(style={background:'green'}) 奇数
div
-var a=1;
case a
when 0
div aaa
when 1
div bbb
when 2
div ccc
default
|没啦
const jade = require('jade');
const fs = require('fs');
var str = jade.renderFile('./view/1.jade', {
pretty: true,
name: "yangze",
json: {width: "200px", height: "200px", background: "red"},
arr: ['aaa', 'bbb', 'ccc'],
content:"<div>123</div>"
});
fs.writeFile('./build/1.html', str, function (err) {
if (err) {
console.log('fail');
} else {
console.log('seccess');
}
});
jade案例
1 | doctype |
- ejs
非侵入式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//1.<%= name %>
//2.<%= json.arr[0].name %>
//3.<%= 12+5 %>
//4.<%= 'asdfasdf' %>
//5.<% include 1.txt %>
<!doctype html>
<html lang="en">
<head>
</head>
<body>
<% for (var i = 0;i < json.arr.length;i++) { %>
<div>
用户名:
<%= json.arr[i].user %>
密码:
<%= json.arr[i].pass %>
</div>
<% } %>
</body>
</html>
const ejs = require('ejs');
ejs.renderFile('./views/1.ejs', {
json: {
arr:[
{user:'blue',pass:'12341234'},
{user:'zhangsan',pass:'12121212'},
{user:'xiaoming',pass:'23452345'}
]
}
}, function (err, data) {
console.log(data);
});
Router
1 | var r=express.Router(); |
multer
body-parser 解析post数据—>application/x-www-form-urlencoded
multer 解析post文件—>multipart/form-data
html
1 | <form action="http://localhost:8080" method="post" enctype="multipart/form-data"> |
node
1 | const express = require('express'); |
consolidate
1 | const consolidate = require('consolidate'); |
MD5
1 | const crypto = require('crypto'); |