__dirname 绝对路径
__filename 绝对路径加文件名

自定义事件

myEmitter = new events.EventEmitter();
myEmitter.on('some', function() {});
myEmitter.emit('some');

工具类

util
util.inherits(Person, events.EventEmitter); 相当于es6的class extends

文件 都有异步:

  1. fs.readFile 读文件
  2. fs.writeFile 写文件
  3. fs.unlink('123.txt') 删除文件
  4. fs.mkdirSync() 创建文件夹
  5. fs.rmdirSync() 删除文件夹

linux的标准输入标准输出流

ls | grep w 检索关键字w的文件
ls | grep w | grep js 双重检索

执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;
标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。

node的http请求也是流,请求是输入流,响应是输出流

使用读写流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var myReadStream = fs.createReadStream(__dirname + '/readMe.txt')
var myWriteStream = fs.createWriteStream(__dirname + '/writeMe.txt')
myReadStream.setEncoding('utf8')

var data = ""
myReadStream.on('data', function(chunk) {
data + = chunk
myWriteStream.write(chunk)
})
myReadStream.on('end', function() {
console.log(chunk)
})

var writeData = 'hello world';
myWriteStream.write(writeData)'
myWriteStream.end()
myWriteStream.on('finish', function() {
console.log('finished')
})

使用管道

1
2
3
var myReadStream = fs.createReadStream(__dirname + '/readMe.txt')
var myWriteStream = fs.createWriteStream(__dirname + '/writeMe.txt')
myReadStream.pipe(myWriteStream)

web服务器

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
var server = http.createServer(function(req, res) {
console.log('Request received')
// 响应纯文本
response.writeHead(200, { 'Content-Type': 'text/plain' })
response.write('Hello from out application')
response.end()

// 响应JSON
response.writeHead(200, { 'Content-Type': 'application/json' })
var myObj = {
name: 'lok',
age: 23
}
response.end(JSON.stringfy(myObj))

// 响应html页面
response.writeHead(200, { 'Content-Type': 'text/html' })
var htmlFile = `HTML片段。。。`

// 使用流
var myReadStream = fs.createReadStream(__dirname + '/index.html', 'uft8')
myReadStream.pipe(response);

})

server.listen(3000, '127.0.0.1')

重构http代码,拆分函数

app.js

1
2
3
4
5
6
7
8
9
10
11
var server = require('./server');
var router = require('./router');
var handler = require('./handler');

var handle = {};
handle["/"] = handler.home;
handle['/home'] = handler.home;
handle['/review'] = handler.review;
handle['/api/v1/records'] = handler.api_records;

server.startServer(router.route, handle);

server.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var http = require('http');
var fs = require('fs');

function startServer(route, handle) {
var onRequest = function(request, response) {
console.log('Request received ' + request.url);
route(handle, request.url, response);
}

var server = http.createServer(onRequest);

server.listen(3000, '127.0.0.1');
console.log('Server started on localhost port 3000');
}

module.exports.startServer = startServer;

router.js

1
2
3
4
5
6
7
8
9
10
11
12
13
var fs = require('fs');

function route(handle, pathname, response) {
console.log('Routing a request for ' + pathname);
if (typeof handle[pathname] === 'function') {
handle[pathname](response);
} else {
response.writeHead(404, { 'Content-Type': 'text/html' });
fs.createReadStream(__dirname + '/404.html', 'utf8').pipe(response);
}
}

module.exports.route = route;

handler.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
var fs = require('fs');

function home(response) {
response.writeHead(200, { 'Content-Type': 'text/html' });
fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(response);
}

function review(response) {
response.writeHead(200, { 'Content-Type': 'text/html' });
fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(response);
}

function api_records(response) {
response.writeHead(200, { 'Content-Type': 'application/json' });
var jsonObj = {
name: "hfpp2012"
};
response.end(JSON.stringify(jsonObj));
}

module.exports = {
home: home,
review: review,
api_records: api_records
}

GET请求

1
2
3
var pathname = req.url;
console.log(url.parse(pathname, true).query)
res.end("123");

POST请求

querystring.parse() 解析字符串

1
2
3
4
5
6
7
8
9
10
11
12
var date = []
req.on('error', function(err) {
console.error(err)
}).on('data', function(chunk) {
data.push(chunk)
}).on('end', function() {
if(data.length > 1e6) {
req.connection.destory()
}
data = Buffer.concat(data).toString()
res.end(querystring.parse(data))
})

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
var express = require('express');
var bodyParser = require('body-parser'); // 引入BodyParse
var fs = require('fs');

var app = express();

// // app.use(bodyParser.urlencoded({ extended: false })); // 使用中间件bodyParse-表单
// app.use(bodyParser.json()); // 使用中间件bodyParse-json

var jsonParser = bodyParser.json();
var urlencodedParser = bodyParser.urlencoded({ extended: false });

app.get('/profile/:id', function (req, res) {
res.send('this is homepage' + req.params.id);
})


app.post('/', urlencodedParser, function (req, res) { //处理post请求,表单提交
console.dir(req);
res.send(req.body);
})

app.post('/upload', jsonParser, function (req, res) { //处理post请求,json提交
console.dir(req.body);
res.send(req.body);
})

app.listen(3000);

console.log('listenning to port 3000')

文件上传

npm install --save multer

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
// server.js
var multer = require('multer')

var createFolder = function (folder) { // 创建文件夹
try {
fs.accessSync(folder);
} catch (e) {
fs.mkdirSync(folder);
}
}

var uploadFolder = './upload'; // 文件夹名
createFolder(uploadFolder);

var storage = multer.diskStorage({// multer 配置
destination: function (req, file, cb) {
cb(null, uploadFolder);
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
cb(null, file.originalname)
}
})

var upload = multer({ storage: storage })

app.get('/form', function (req, res) {
var form = fs.readFileSync('./form.html', { encoding: "utf8" });
res.send(form);
})


app.post('/upload', upload.single('logo'), function (req, res) {
console.log(req.file) // 上传的文件信息
res.send({ 'ret_code': 0 });
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//  form.html
<!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>
<form action="/upload" method="post" enctype="multipart/form-data">

<h2>单图上传</h2>
<input type="file" name="logo">
<input type="submit" value="提交">

</form>
</body>

</html>

模板引擎

npm install 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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// server.js
app.set('view engine', 'ejs');

app.get('/form/:name', function (req, res) {
var person = req.params.name;
var data = { person: person, job: 'artist', hobbies: ['sing', 'dance', 'basketball'] }
// res.sendFile(__dirname + '/form.html');
res.render('form', { data }) // 渲染form.ejs .ejs可省略
})

// views/form.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>
<%- include('partials/header') -%> //引用其他模板
<h1><%= data.person %></h1>
<ul>
<% data.hobbies.forEach(item => { %> // 循环数组
<li><%= item %></li>
<% }) %>
</ul>
<form action="/upload" method="post" enctype="multipart/form-data">

<h2>单图上传</h2>
<input type="file" name="logo">
<input type="submit" value="提交">

</form>
</body>

</html>

// views/partials/header.ejs
<nav>
<ul>
<li><a href="">home</a></li>
<li><a href="">about</a></li>

</ul>
asd
</nav>

中间件

请求响应中间的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var express = require('express')

var app = express();

app.use(express.static('public')); // 静态文件目录public

app.use(function (req, res, next) {
console.log('first middleware');
next();
console.log('first middleware after');
})

app.use('/home', function (req, res, next) {
console.log('second middleware');
res.send('ok');
})

app.listen(3001);

输出顺序

first middleware

second middleware

first middleware after

路由中间件

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
// index.js 入口文件
var express = require('express');

var app = express();

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

app.use(indexRouter); //路由中间件
app.use(usersRouter); //路由中间件

app.listen(3000);
console.log('index listening to port 3000')

// users.js 路由用户
var express = require('express');

var router = express.Router();

router.get('/users', function (req, res, next) {
res.send('user');
})

module.exports = router;

// index.js 路由根
var express = require('express');

var router = express.Router();

router.get('/', function (req, res, next) {
res.send('root');
})

module.exports = router;

mongoose

nodejs 操作mongodb的库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var mongoose = require('mongoose');

mongoose.connect('mongodb+srv://hqwuzhaoyi:hqwuzhaoyi@todolists-eu7nu.mongodb.net/test?retryWrites=true&w=majority', {
useNewUrlParser: true,
useUnifiedTopology: true
}); // 连接地址,后面option是github文档推荐的

var todoSchema = new mongoose.Schema({
item: String
})// 创建数据模型


var Todo = mongoose.model('Todo', todoSchema);//创建连接模型,操作Todo就是操作数据库


var itemOne = Todo({ item: 'buy flowers' }).save(function (err) { // 保存一条row
if (err) throw err;
console.log('item saved');
})

mongoose list页面增加删除

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

var bodyParser = require('body-parser')

var urlencodedParser = bodyParser.urlencoded({ extended: false })


// mongoose
var mongoose = require('mongoose');

mongoose.connect('mongodb+srv://hqwuzhaoyi:hqwuzhaoyi@todolists-eu7nu.mongodb.net/test?retryWrites=true&w=majority', {
useNewUrlParser: true,
useUnifiedTopology: true
});

var todoSchema = new mongoose.Schema({
item: String
})

var Todo = mongoose.model('Todo', todoSchema);

// var itemOne = Todo({ item: 'buy flowers' }).save(function (err) {
// if (err) throw err;
// console.log('item saved');
// })

// var data = [{ item: 'get milk' }, { item: 'walk dog' }, { item: 'kick some coding ass' }]

module.exports = function (app) {
app.get('/todo', function (req, res) {
Todo.find({}, function (err, data) { //查到所有的row
if (err) throw err;
res.render('todo', { todos: data })
})
})

app.post('/todo', urlencodedParser, function (req, res) {
var itemOne = Todo(req.body).save(function (err, data) { //添加发过来的row
if (err) throw err;
res.json(data) //让请求不报错,给个响应,是什么无所谓
console.log('item saved');
})
})

app.delete('/todo/:item', function (req, res) {
// data = data.filter(function (todo) {
// return todo.item.replace(/ /g, '-') !== req.params.item;
// })
Todo.find({ item: req.params.item.replace(/-/g, " ") }).remove(function (err, data) { //item传过来的-格式换成空格,删除collection中的row
if (err) throw err;
res.json(data);
console.log('item delete');
})

})
}