Express

初识Express

基于Node.js,快速、开放、极简的Web开发框架,与内置的http模块类似

Express的本质:就是一个npm上的第三方包

http内置模块用起来复杂,开发效率低;Express是基于内置的http模块进一步封装出来的

Express能做什么,

Web网站服务器

API接口服务器

使用Express可以调用特定HTTP动词(GET,POST)函数和URL模式(路由)函数,还可以指定模版(视图)引擎种类。

可以使用Express中间件添加对cookie,会话,用户,获取参数等

路由

下面是一个Hello World的事例

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

const app = express()

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

app.listen(80, ()=>{
console.log('express server running at http://127.0.0.0.1')
})

先通过require()导入Express模块,创建app的Express应用。

该应用可以进行HTTP请求、配置中间件、渲染HTML视图、注册模版引擎以及修改应用程序设置

从而控制应用的行为

app.get()是路由定义。该方法指定一个回调函数,在每监听到一个关于站点根目录路径的HTTP请求时调用。用send()函数返回字符串“Hello World”

最后在端口80上启动服务器。

路由方法

1
2
3
4
app.get("/", (req, res) => {
res.send("Hello World!");
});

回调函数将请求和响应对象作为参数。该函数直接调用res响应的send()方法,返回字符串。

还有其他响应方法:

res.json()发送JSON响应、res.sendFile()来发送文件

注意: 当调用回调时,第一个参数始终是请求,第二个参数始终是响应。应合理命名参数

Express应用对象还提供其他所有HTTP动词定义的路由处理方法,大多数的使用方式一致:

checkout() ,copy(), delete() ,get(), head(), lock(), merge(), mkactivity(), mkcol(), move(), m-search(), notify(), options(), patch(), post(), purge(), put(), report(), search(), subscribe(), trace(), unlock(), unsubscribe().

有一个特殊的路由方法 app.all() ,它可以在响应任意HTTP方法时调用。用于在所有HTTP请求方法的路径上加载中间件函数。例如,无论使用GET、POST、PUT、DELETE等等,都会对路由 “/secret” 执行下面程序

1
2
3
4
app.all('/secret',(req,res,next)=>{
console.log('Accessing the secret section...')
next() //控制权传递给下一个处理器
})

路由路径

路由路径与请求方法相结合,定义了可以发出请求的端点。路由路径可以是字符串、字符串模式或正则表达式 ?+*()

例如:

关于字符串模式的路由路径示例:

此路由匹配 abcdacd

1
2
3
app.get('/ab?cd',(req,res)=>{
res.send('abc')
})

此路由匹配 abcdabbcd

1
2
3
app.get('/ab+cd',(req,res)=>{
res.send('abc')
})

此路由将匹配 abcd abxcd abRANDcd

1
2
3
app.get('/ab*cd',(req,res)=>{
res.send('abc')
})

基于正则表达式的路由示例:

此路由将匹配其中带有”a”的任何内容

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

此路由将匹配butterfly 和 dragonfly ,但不匹配butterflyman,dragnoflyman等

1
2
3
app.get(/.*fly$/, (req, res) => {
res.send('/.*fly$/')
})

路由参数

路由参数是命名的URL段,用于捕获URL中该位置指定的值。捕获到的值填充到 req.params 对象中,路径中指定的参数名称作为它们各自的键

1
2
3
4
5
6
//这里的id是一个动态参数,可以通过 :参数名 的形式
app.get('/usr/:id',(req,res)=>{
// req.params是动态匹配到的动态参数
console.log(req.params)
res.send(req.params)
})

比如,发送请求到http://127.0.0.0.1/usr/2时,返回一个对象 { “id”:2 }

路由参数的名称必须由 “word characters” ([A-Za-z0-9_])组成

由于连字符(-)和点(.)按字面解释,因此可以与路由参数一起使用

1
2
3
Route path: /flights/:from-:to
Request URL: http://localhost:3000/flights/LAX-SFO
req.params: { "from": "LAX", "to": "SFO" }

查询参数

res.query

1
2
3
4
5
6
7
8
//监听GET和POST请求
app.get('/usr',(req,res)=>{
//调用express提供的res.send()方法,向客户端响应一个json对象
res.send({name:'zs', age:20})
//通过req.query可以获取到客户端发送过来的查询参数
//默认情况下,req.query是一个空对象
console.log(req.query)
})

路由处理程序

可以使用多个回调函数,其行为类似中间件来处理请求。唯一的例外是这些回调可能会调用next(‘route’) 来绕过剩余的路由回调。

路由处理程序可以是函数、函数数组或两者组合

单个回调函数处理

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

多个回调函数可以处理一个路由

1
2
3
4
5
6
app.get('/example',(req,res,next)=>{
console.log('hello-1')
next()
},(req,res)=>{
res.send('hello-2')
})

一组回调函数可以处理路由例如

1
2
3
4
5
6
7
8
9
10
11
12
13
const a = function(req,res,next){
console.log('Aa')
next()
}
const b = function(req,res,next){
console.log('Bb')
next()
}
const c = function(req,res,next){
res.send('Cc')
}

app.get('/example',[a,b,c])

独立函数和函数数组的组合来处理路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const a = function(req,res,next){
console.log('Aa')
next()
}
const b = function(req,res,next){
console.log('Bb')
next()
}

app.get('/example',[a,b],(req,res,next)=>{
console.log('hello-1')
next()
},(req,res)=>{
res.send('hello-2')
})

响应方法

方法 描述
res.download() 提示要下载的文件。
res.end() 结束响应过程。
res.json() 发送 JSON 响应。
res.jsonp() 发送带有 JSONP 支持的 JSON 响应。
res.redirect() 重定向请求。
res.render() 渲染视图模板。
res.send() 发送各种类型的响应。
res.sendFile() 将文件作为八位字节流发送。
res.sendStatus() 设置响应状态码并将其字符串表示形式作为响应正文发送。

模块化路由

app.route()

1
2
3
4
5
6
7
8
9
app.route('/user').get((req,res) =>{
res.send('get a user')
})
.post((req,res)=>{
res.send('post a user')
})
.put((req,res)=>{
res.send('put a user')
})

express.Router

使用这个类来创建模块化、可安装路由处理程序。一个Router实例是一个完整的中间件和路由系统;因此,它通常被称为”mini-app”

以下示例将路由创建为模块,在其中加载中间件函数,定义一些路由,并将路由模块安装在主应用程序的路径上。

创建一个route.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const express = require('express')
const router = express.Router()

router.use((req,res,next)=>{
console.log('Time:',Date.now())
next()
})

router.get('/',(req,res)=>{
res.send('Home page')
})

router.get('/about',(req,res)=>{
res.send('About page')
})

module.exports = router

然后在应用程序加载路由模块

1
2
3
const route = require('route.js')
// ...
app.use('/main',route) //main是路径前缀

该应用程序现在将能够处理对 /main/main/about 的请求,以及调用特定于路由的 timeLog 中间件函数。

注意:app.use()函数的作用,用来注册全局中间件,后续会介绍中间件