f10@t's blog

express学习(一)-基于NodeJS的Web框架

字数统计: 2.1k阅读时长: 9 min
2021/07/14

哎前端,自己就没踏踏实实学过前端的玩意儿,嚷嚷着要学vue要学angular,结果都是接触个皮毛,完后屁颠屁颠回去学Java了...,今天项目需要,学学express,一个基于NodeJS的快速开发web应用的框架(属于Nodejs的后端框架),目的是学会基本使用。vue这些前端框架回头专门记录学学(我也好想会做好看的前端呜呜呜)

express-title

入门demo

首先新建一个目录然后npm init来初始化这个工程,主要是生成package.json这个依赖管理文件,然后我们npm install express --save来安装express,可以自定义入口为app.js(一般的习惯),然后代码如下:

1
2
3
4
5
6
7
8
9
10
11
const express = require('express')
const app = express()
const port = 9999

app.get('/', (req, res)=>{
res.send("express!")
})

app.listen(port, ()=>{
console.log(`express is listening on port: ${port}`);
})

然后node app.js就可以启动应用了,访问根目录就可以看到我们绑定的路由以及对应的handler函数了。

当然一般可以使用express-generator来完成这个工作,安装:npm install -g express-generator。然后就可以新建工程了,比如:

image-20210714122920878

然后在其目录下npm install安装依赖就可以了。最后的目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
├── app.js
├── bin
└──www
├── node_modules
├── public
│ ├─images
│ ├─javascripts
│ └─stylesheets
│ └── style.css
├── routes
│ ├── index.js
│ └── users.js
└── views
├── error.pug
├── index.pug
└── layout.pug

如果你要在视图层使用html作为模板文件的话,需要在app.js中修改他的默认模板引擎,并且要安装ejs模块(npm install ejs --save),修改后的代码如下:

1
2
3
4
5
// view engine setup
// 修改视图层引擎为html
app.set('views', path.join(__dirname, 'views'));
app.engine('.html', require('ejs').__express)
app.set('view engine', 'html');

这样就可以使用html文件了。

路由设置

首先我们来确立几个基本概念,就照着上面的demo(这里再粘贴一下):

1
2
3
const express = require('express')
const app = express()
const port = 9999

首先app这个变量,它是express的一个实例,下面我们定义了一条路由规则:

1
2
3
app.get('/', (req, res)=>{
res.send("express!")
})

定义路由规则的语法是这样的:app.METHOD(URL, HANDLER),其中Handler由请求和响应组成,比如上面的代码中就用响应变量res回执了一个字符串。

URL路径

官方给了几个例子,分别对应不同的HTTP请求:

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
// 请求根
app.get('/', function (req, res) {
res.send('root')
})

// 请求/about页面
app.get('/about', function (req, res) {
res.send('about')
})

// 请求/random.text
app.get('/random.text', function (req, res) {
res.send('random.text')
})

// 附带规则
// 请求abd或者abcd,b?意思就是有没有?前面这个b都可以
app.get('/ab?cd', function (req, res) {
res.send('ab?cd')
})

// 类似上面,意思中间可以是一堆b,比如abbbbcd
app.get('/ab+cd', function (req, res) {
res.send('ab+cd')
})

// 和上面一个意思,只不过中间可以不是b,比如abq345281cd
app.get('/ab*cd', function (req, res) {
res.send('ab*cd')
})

// 和ab?cd一个意思,即cd这俩可有可无=>abe或者abcde
app.get('/ab(cd)?e', function (req, res) {
res.send('ab(cd)?e')
})

// 正则
// 只要带个a就可以访问
app.get(/a/, function (req, res) {
res.send('/a/')
})

// 以fly结尾就可以,比如butterfly
app.get(/.*fly$/, function (req, res) {
res.send('/.*fly$/')
})

路由参数

当然我们也要处理用户传递的数据的,老规矩,get的参数或者post的参数呗。先看get的,处理方法类似go语言:

1
2
3
app.get('/users/:userId/books/:bookId', function (req, res) {
res.send(req.params)
})

上面这个url传递过来后,就可以拿到userId和bookId这两个变量

当然,你也可以用这种骚气一点的处理方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 带个'-'来匹配get的参数
Route path: /flights/:from-:to
Request URL: http://localhost:3000/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }

// 同理,也可以用'.'来分隔匹配参数
Route path: /plantae/:genus.:species
Request URL: http://localhost:3000/plantae/Prunus.persica
req.params: { "genus": "Prunus", "species": "persica" }

// 当然,还有正则
Route path: /user/:userId(\d+)
Request URL: http://localhost:3000/user/42
req.params: {"userId": "42"}

处理程序(Handler)

上面demo的例子只有一个handler函数,实际上也可以组合使用多个handler函数进行跳转,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require('express')
const app = express()
const port = 9999

app.get('/test', (req, res, next)=>{
console.log("this request will be handled by next!")
next() // 交由下一个handler处理
}, (req, res)=> {
res.send("ok")
})

app.listen(port, ()=>{
console.log(`express is listening on port: ${port}`);
})

我们就可以在控制台看到跳转,以及最终回显的结果

image-20210714142325049
image-20210714142212956

当然你也可以单独独立定义函数,然后组成数组,交由app来进行管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require('express')
const app = express()
const port = 9999


var func1 = function(req, res, next) {
console.log("this is func1")
next()
}

var func2 = function(req, res, next) {
console.log("this is func2")
next()
}

var func3 = function(req, res, next) {
res.send("hello!")
}

app.get('/test', [func1, func2, func3])

app.listen(port, ()=>{
console.log(`express is listening on port: ${port}`);
})
image-20210714142724475
image-20210714142731697

上面的例子是都绑定到了get方法,此外,你也可以将这些方法绑定到不同的方法里:

1
2
3
4
5
6
7
8
9
10
app.route('/book')
.get(function (req, res) {
res.send('Get a random book')
})
.post(function (req, res) {
res.send('Add a book')
})
.put(function (req, res) {
res.send('Update the book')
})

比如上面的代码就把不同的处理程序绑定到了/book路径下的不同请求方法中。

响应可执行的方法(Method)

如果以下的方法没有被调用的话,服务端和客户端的通信将一直挂起。比如我们demo里的send方法就可以结束一次请求-响应的循环。

Method Description
res.download() Prompt a file to be downloaded.
res.end() End the response process.
res.json() Send a JSON response.
res.jsonp() Send a JSON response with JSONP support.
res.redirect() Redirect a request.
res.render() Render a view template.
res.send() Send a response of various types.
res.sendFile() Send a file as an octet stream.
res.sendStatus() Set the response status code and send its string representation as the response body.

express.Router()

定义Handler的方式可能有点乱,还有一种模块化的管理路由的方式就是使用express.Router,我们单独在一个文件中写路由规则,然后导出这个模块使用即可。一个例子如下:

首先我们使用express初始化后的工程,在routers/index.js文件中写我们的规则:

1
2
3
4
5
6
7
8
9
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index.html');
});

module.exports = router;

然后 views下写我们的视图层文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<title>Hello Express</title>
<link href="stylesheets/style.css" rel="stylesheet">
</head>
<body>
<h2>Hello Express</h2>
</body>

</html>

默认express应用的监听端口是3000,这里使用npm start app.js来启动我们的应用,其本质就是调用了bin目录下的www脚本,其实还是node调用,只不过定义了端口等信息。然后访问网页就可以看到内容了(304是因为我访问过了):

image-20210714171804025

静态资源注册

比如图片这些东西直接使用express自带的static函数就可以注册了,例子如下:

1
app.use(express.static('public'))

上面的代码就把public目录下的所有静态资源都开放给外界使用,比如http://localhost:3000/css/style.css就可以被访问到。如果你还有其他目录的资源想要开放,那么也是使用上面的函数进行注册就可以了。

此外,你也可以将资源挂在到一个虚拟的路径下面,比如:

1
app.use('/static', express.static('public'))

那么上面那个css文件的访问路径就变成了http://localhost:3000/static/css/style.css。上面这种注册方式是因为你的注册语句是写在app.js里面的,如果说你写到其他文件里,express是找不到这个public文件夹的,所以建议这样注册,其中__dirname就是你的项目根目录。

1
app.use('/static', express.static(path.join(__dirname, 'public')))

参考学习

Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网 (expressjs.com.cn)

CATALOG
  1. 1. 入门demo
  2. 2. 路由设置
    1. 2.1. URL路径
    2. 2.2. 路由参数
    3. 2.3. 处理程序(Handler)
    4. 2.4. 响应可执行的方法(Method)
    5. 2.5. express.Router()
  3. 3. 静态资源注册
  4. 4. 参考学习