JavaScript-Express

Express

1.Express框架

基于 Node.js 平台,快速、开放、极简的 web 开发框架。
它是用于后台NodeJs的框架,与JQuery/Bootstrap/vue.js/AngularJs这类前端框架是不一样的!
Express 不对 Node.js 已有的特性进行二次抽象,我们只是在它之上扩展了 Web 应用所需的基本功能。
丰富的 HTTP 快捷方法和任意排列组合的 Connect 中间件,让你创建健壮、友好的 API 变得既快速又简单。

对比原生Node.js
使用原生Node.js开发,会发现有很多问题:
- 呈现静态页面很不方便,需要处理每个HTTP请求,还要考虑304缓存问题.
- 路由处理代码不直观清晰,需要写很多正则表达式和字符串函数.
- 开发者不能集中精力写业务,要考虑很多其他的东西.

官网:http://expressjs.com/
中文官网:http://www.expressjs.com.cn/

2.安装

npm install express –save #即可安装最新版本的Express

  • Express4.x与3.x版本的差别非常大,我们使用4.x

2.1. 基本使用

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
//  引入express 框架
var express = require('express');
// console.log(express);

// 创建 express 的 HTTP服务器
var app = express();
// 指定框架的模版引擎,无需导入
app.set('view engine', 'ejs');

// 指定静态化的目录
app.use('/static', express.static('./static'));


// 设置路由规则
app.get('/', function(req, res){
// 响应输出
res.send('Hello Express~~~');
});

app.get('/test', function(req, res){
// 响应输出
res.send('这是test页面');
});

app.get('/user', function(req, res){
// 绑定并输入数据
res.render('user', {
'userlist' : [
'钢铁侠 屎大颗',
'绿巨人 浩克',
'美队 史蒂文',
'雷神 托尔',
'邪神 洛基',
'蜘蛛侠 彼得帕克'
]
});

});

// 设置请求监听
app.listen(3000);

2.2. 路由处理

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
//  引入express 框架
var express = require('express');
// 创建 express 的 HTTP服务器
var app = express();

// 支持所有的请求方式, 实现中间件的功能
app.all('/t', function(req, res, next){
console.log(new Date().toString());
next();
});


// 设置路由规则
app.get('/', function(req, res){
// 响应输出
res.send('Hello Express~~~');
});
// GET
app.get('/t', function(req, res){
// 响应输出
res.send('GET 请求');
});
// POST
app.post('/t', function(req, res){
// 响应输出
res.send('POST 请求');
});

// DELETE
app.delete('/t', function(req, res){
// 响应输出
res.send('DELETE 请求');
});


// 路由方法默认匹配 pathnameb部分,忽略get参数
// 对大小写不敏感
app.get('/aaa', function(req,res){
console.log(req.query);
res.send('3A页面 ');
});

// 路由路径 默认express path-to-regexp 匹配路由路径

// 正则路由 /stu/1234567890/tom
app.get(/^\/stu\/(\d{10})\/(\w+)$/, function(req,res){
console.log(req.params);
res.send('学员的学号是: '+ req.params[0]);
});

// 路由参数
// :xx 表示参数占位,使用req.params读取参数
app.get('/tch/:tid', function(req,res){
console.log(req.params);
res.send('老师的工号是: '+req.params.tid);
});

// 多个路由参数
app.get('/goods/:name/:num', function(req,res){
// 参数限制
var name = req.params.name;
var num = req.params.num;
if (/\d+/.test(num)) {
res.send('商品名: ' + name + ', 入库: ' + num + '件');
} else {
res.send('请填写正确的数量');
}
});


// 设置请求监听
app.listen(3000);

2.3. 对模版引擎的支持

2.4. 静态文件/目录处理

3.路由

3.1. 路由的访问方式

3.2. 路由路径

3.3. 响应方法
res.download() 提示下载文件。
res.end() 终结响应处理流程。
res.json() 发送一个JSON格式的响应。
res.jsonp() 发送一个支持JSONP的JSON格式的响应
res.redirect() 重定向请求。
res.render() 渲染视图模板。
res.send() 发送各种类型的响应。
res.sendFile() 以八位字节流的形式发送文件。
res.sendStatus() 设置响应状态代码,并将其以字符串形式作为响应体的一部分发送。

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

var express = require('express');
var app = express();

// 路由重名
// 路由中间件
app.get('/kk',function(req,res,next){
console.log(1);
next();
});

app.get('/kk',function(req,res){
console.log(2);
res.send('响应完成');
});


// 匹配冲突
app.get('/:goods/:num',function(req, res, next){
// 做查询/匹配...
if (false) {
console.log(1);
res.send('商品' + req.params.goods + '数量:'+req.params.num);
} else {
next();
}
});

app.get('/admin/login',function(req,res){
console.log(2);
res.send('登录界面');
});

app.listen(3000);

4.中间件

4.1. 中间件概念

4.2. express路由 具有的中间件特性

4.3. app.use()的特性

app.use() 就是一个中间件,与get()/post()..方法不用的是,
它的URL不是精确匹配,而是模糊匹配

4.4. app.use()使用

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(function(req, res, next){
console.log(new Date().toString());
next();
});

// 中间件
app.use('/admin',function (req, res) {
res.write(req.originalUrl + '\n'); // 完整的URL
res.write(req.baseUrl + '\n'); // 基础URL
res.write(req.path + '\n'); // 除去基础以外的URL
res.end('后台...');
});

app.listen(3000);

4.5. 静态资源服务的说明

4.6. 404 页面的说明


5.模版引擎,渲染页面

5.1. 模版引擎 的设置和使用

5.2. 原生的 end() 与express的 send() 的区别

5.3. 设置响应头 和 状态码 和 MIME类型

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

var express = require('express');
var app = express();

// 指定框架的模版引擎,无需导入
app.set('view engine', 'ejs');

// 提供静态资源服务
// app.use(express.static('./static'));

// 默认使用 .ejs 为模版文件,目录views
// app.set('views', './pages');

app.get('/', function (req,res){
// 绑定数据并渲染视图
res.render('user', {
'userlist' : [
'钢铁侠 屎大颗',
'绿巨人 浩克',
'美队 史蒂文',
'雷神 托尔',
'邪神 洛基',
'蜘蛛侠 彼得帕克'
]
});
});

app.get('/hh', function (req,res){
// node.js end()
// express send()
// 二进制
// res.send(new Buffer('HOOH~'));

// str
// res.send('HOOH~');

// JSON
// res.send({name:"静静", sec:0});
// ARRAY
res.send([15,168,19681,9681,98,986884,true]);

});

app.listen(3000);

6.GET 与 POST

6.1 GET

GET请求的参数在URL中.
原生node中,要想得到get参数,需要借助于url模块来识别参数字符串.
在Express中,不需要使用url模块了.可以直接使用req.query对象得到GET参数

6.2 POST

GET请求的参数是隐蔽传参(在请求体中).
POST请求在Express中不能直接获得,必须使用body-parser模块.使用后,将可以用req.body得到参数.
但是如果表单中含有文件上传,那么还是需要使用formidable模块.

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

var express = require('express');
var bodyParser = require('body-parser');
var app = express();

// 指定框架的模版引擎,无需导入
app.set('view engine', 'ejs');


// parse application/x-www-form-urlencoded
// 解析 post数据
app.use(bodyParser.urlencoded({ extended: false }));

//GET参数
app.get('/', function (req,res){
console.log(req.query);
res.send('GET 完成');
});

app.get('/form', function (req,res){
res.render('form');
});


// POST
app.post('/', function (req,res){
console.log(req.body);
res.send('POST 完成');
});


app.listen(3000);

7.Express对数据库的支持

7.1 数据库集成

7.2 连接mysql数据库

7.3 使用数据库 - 查/增/改/删

7.4 连接池

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

var express = require('express');
var mysql = require('mysql');
var app = express();

app.get('/', function(req,res){
// 连接数据库
var connection = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : '123456',
database : 's86'
});
// 开启数据库
connection.connect();

// var sql = 'SELECT * FROM user';
var sql = 'UPDATE user SET age="19" WHERE id="1"';
connection.query(sql, function (err, result) {
if (err) {
console.log('执行出错: ' + err);
return;
}

console.log(result);
res.send(result);
});

connection.end();
});


app.listen(3000);

8.Web Socket和Socket.IO框架

8.1. HTTP的问题

HTTP无法轻松实现 实时应用:

  • HTTP协议是无状态的,服务器只会响应来自客户端的请求,但是它与客户端之间不具备持续连接。(无法长时持续连接)
  • 我们可以捕获浏览器上发生的事件(比如用户点击了button),这个事件可以产生与服务器的数据交互(比如Ajax)。
    但是,反过来却是不可能的:服务器端发生了一个事件,服务器无法将这个事件的信息实时主动通知它的客户端。只有在客户端查询服务器的当前状态的时候,所发生事件的信息才会从服务器传递到客户端。(无法主动输出信息)

但是,HTTP协议也能做聊天室这种’长连接’的东西,它是这么实现的:

  • 长轮询:客户端每隔很短的时间,都会对服务器发出请求,查看是否有新的消息,只要轮询速度足够快,例如1秒,就能给人造成交互是实时进行的印象。这种做法是无奈之举,实际上对服务器、客户端双方都造成了大量的性能浪费。
  • 长连接:客户端只请求一次,但是服务器会将连接保持,不会返回结果(想象一下我们没有写res.end()时,浏览器的小菊花会一直转)。服务器有了新数据,就将数据发回来,又有了新数据,就将数据发回来,而一直保持挂起状态。这种做法的也造成了大量的性能浪费。

8.2. WebSocket

WebSocket协议能够让浏览器和服务器全双工实时通信,互相的,服务器也能主动通知客户端了。

  • WebSocket的原理非常的简单:利用HTTP请求产生握手,HTTP头部中含有WebSocket协议的请求,所以握手之后,二者转用TCP协议进行交流(QQ的协议)。现在的浏览器和服务器之间,就是QQ和QQ服务器的关系了。
    所以WebSocket协议,需要浏览器支持,更需要服务器支持。
  • 支持WebSocket协议的浏览器有:Chrome 4、火狐4、IE10、Safari5
  • 支持WebSocket协议的服务器有:Node、Apache Tomcat/7.0.27、Nginx1.3

8.3. Socket.IO

用原生Node搭建 WebSocket协议的服务 非常麻烦,我们使用写好的模块: Socket.IO
它屏蔽了所有底层细节,让顶层调用非常简单。
并且还为不支持WebSocket协议的浏览器(IE),提供了长轮询的透明模拟机制。
Node的单线程、非阻塞I/O、事件驱动机制,使它非常适合Socket服务器。

官网:http://socket.io/


chat_demo

初始化:

1
npm init | 聊天室 | index.js

安装的组件:

1
2
3
npm install express --save
npm install ejs --save
npm install socket.io --save

说明:

1
2
Express与Socket.IO
Express框架可以和Socket.IO搭配使用,但是不能像通常的Express程序那样,用app.listen进行监听了,而是采用一种固定的模式.

官方 画板 示例:
https://socket-io-whiteboard.now.sh/
官方 聊天室 示例:
https://socket-io-chat.now.sh/
官方socket.io 仓库:
https://github.com/socketio