路由基础
路由是指确定应用程序如何响应客户端对特定端点的请求,该特定断点是URL和特定的HTTP请求方法(GET,POST)每个路由可以具有一个或多个处理程序函数,这些函数在匹配该路由时执行。路由定义采用以下结构:
app.METHOD(PATH,HANDLER)
- App是Experss实例
- METHOD是小写的HTTP请求方法
- PATH是服务器上的路径
- HANDLER是当前路由匹配时执行的功能
app.post('/',function (req,res){
res.send("hello,post")
})
请求对象
Express应用使用路由回调函数的参数,request
和response
对象来处理请求和响应的数据
app.get('/',function(req,res){
console.log(req,url) //请求地址
console.log(req.method) //请求方法
console.log(req.headers) //请求头
console.log("请求参数:",req.query)
})
响应对象
使用node.js原生的发送数据的方法
//结束响应后,发送数据
res.end("hello,world")
//直接发送数据
res.write("hello")
//使用express中的send方法发送数据
res.send({foo:"bar"}) //发送对象,实际发送一个json字符串
res.status(404).send("sorry") //发送状态码和内容
//发送cookie
res.cookie('foo','bar') //name value
res.cookie('a',123)
案例
通过该案例创建一个简单的CRUD接口服务,从而掌握Express的基本用法。
需求:实现对任务清单的CRUD接口服务
- 查询任务列表:get/todos
- 根据ID查询单个任务:get/todos/:id
- 添加任务:post/todos
- 修改任务:PATCH/todos
- 删除任务:DELETE/todos/:id
路由设计
中间件
中间件
Express的最大特色,也是最重要的一个设计,就是中间件。一个Express应用,就是由许许多多的中间件来完成的。 不去修改自己的代码,以此来扩展或者处理一些功能
在不能干扰原来的流程,同时增加新的工序
AOP面向切面编程
- 将日志记录,性能统计,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率和可维护性。
- 就是在现有代码程序中,在程序声明周期或者横向流程中,加入/减去一个或多个功能,不影响原有的功能
Express中的中间件
在Express中,中间件就是一个可以访问请求对象、响应对象和调用next方法的一个函数
在中间件函数中可以执行以下任何任务:
- 修改任何代码
- 修改request或者response响应对象
- 结束请求响应周期
- 调用下一个中间件
//使用案例
const express = require('express')
const app = express()
require('dotenv').config()
const port = process.env.PORT || 5000
//req:请求对象
//res:响应对象
//next:下一个中间件
//此中间件对于任何请求都会响应,然后在匹配对应的请求类型执行
//因此中间件函数需要放在最上面,有顺序性
app.use((req,res,next)=>{
console.log(req.method,req.url,Date.now())
//交出执行权,往后继续匹配执行
next()
})
app.get('/' , (req , res)=>{
res.send('hello from simple server :)')
})
app.listen(port , ()=> console.log('> Server is up and running on port : ' + port))
注意:如果当前的中间件功能没有结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件功能。否则,该请求将会被挂起
应用程序级别中间件
//不关心请求路径:
app.use(function(req,res,next){
console.log("time:",Date.now())
next()
})
//限定请求路径:
app.use('./user/:id',function(req,res,next){
console.log("Requset type:",req.method)
next()
})
//限定请求路径+请求方法:
app.get('/user/:id',funtion(req,res,next){
res.send("USER")
})
//多个处理函数,两个函数都会被执行,处理函数可以有多个
app.use('/user/:id',function(req,res,next){
console.log("Request URL",req.originalUrl)
next()
},function(req,res,next){
console.log('Request Type:',req.method)
next()
})
要从路由器中间件堆栈中跳过其余中间,请调用`next('route')
将控制权传递给下一条路由。
注意:next(‘route’)仅在使用app.METHOD()或者router.METHOD()函数加载的中间件函数中有效
中间件也可以在数组中声明为可重用。此示例显示了一个带有中间件子堆栈的数组,该子堆栈处理对/user/:id
路径的GET请求
const express = require('express')
const app = express()
require('dotenv').config()
const port = process.env.PORT || 5000
function logOriginalUrl(req,res,next){
console.log("Request URL:",req.originalUrl)
next()
}
function logMethod(req,res,next){
console.log("Request Type:",req.method)
next()
}
var logStuff = [logOriginalUrl,logMethod]
app.get('/' ,logStuff, (req , res,next)=>{
res.send('hello from simple server :)')
})
app.listen(port , ()=> console.log('> Server is up and running on port : ' + port))
错误处理中间件
已与其他中间件函数相同的方式定义错误处理中间件函数,除了使用四个参数而不是三个参数(特别是使用签名(err,req,res,next))之外:
app.use(function (err,req,res,next){
console.error(err.stack)
res.status(500).send("Something broke!")
})
错误处理中间件始终带有四个参数。您必须提供四个参数以将其标识为错误处理中间件函数,即使不需要使用改next对象,也必须指定他以维护签名,否则,该next对象将被解释为常规中间件
app.use((err,req,res,next)=>{
res.status(500).json({
error:err.message
})
})
如果将任何内容传递给该next()函数(字符串除外‘route’),Express都会将当前请求视为错误,并且将跳过所有剩余的非错误处理路由和中间件函数。
app.get('/gets' , (req , res,next)=>{
fs.readFile("./db123.json",(err,data)=>{
//发现错误,则交给错误处理中间件处理
if (err) next(err)
res.send(data)
})
})
//最后挂载错误处理中间件
//错误处理中间件一定是四个参数
app.use((err,req,res,next)=>{
res.status(500).json({
err:err.message
})
})
通常会在所有路由之后配置处理404的内容,请求会从上到下依次匹配
//在所有的路由后面,处理404的相关请求
app.use((req,res,next)=>{
res.status(404).send("404 not Found")
})
路由方法
路由方法是从HTTP方法之一派生的,并附加到express该类的实例,
有一种特殊的路由方法,app.all()
用于为所有HTTP请求方法的路径加载中间件功能。例如,无论是使用GET,POST,PUT,DELETE还是http模块
支持的任何其他HTTP请求方法,都会对路由/secret
的请求执行以下处理程序
app.all('/secret',function(req,res,next){
console.log("Accessing the secret section...")
next()
})
路由路径
//此路由路径会将请求匹配到/about
app.get('/about',function(req,res){
res.send('about')
})
//此路由路径会将请求匹配到/random.text
app.get('/random.text',function(req,res){
res.send("random.text")
})
//此路由路径将acd和匹配abcd
app.get('/ab?cd',function(req,res){
res.send('ab?cd')
})
//这条路线的路径将会匹配abcd、abbcd、abbbcd
app.get('/ab+cd',function(req,res){
res.send("ab+cd")
})
//基于正则表达式的路由路径
//匹配其中带有"a"的任何内容
app.get('/a/',function(req,res){
res.send("/a/")
})
//匹配butterfly和dragonfly
app.get('/.*fly$/',function(req,res){
res.send('/.*fly$/')
})
路由路径参数
路由参数被命名为URL段,用于捕获URL中在其位置处指定的值,捕获的值将填充到req.params
对象中,并将路径中指定的route参数的名称作为其各自的键
app.get('/users/:id',(req,res)=>{
console.log(req.params.id)
res.send("get/users/:id")
})
路径参数的名称必须由“文字字符”[[A-Za-z0-9_]]组成。由于连字符(-)和点(.)是按字面解释的,因此可以将它们与路由参数一起使用,以实现有用的目的
Route path:/flights/:from:to
Request URL:http://locoalhost:3000/flights/LAX-SFO
req.params:{"from":'LAX','to':"SFO"}
要更好的控制可以由route参数匹配的确切字符串,可以在括号(())后面附加一个正则表达式:
Route path:/user/:userID(\d+)
Request URL:http://localhost:3000/user/42
req.params:{"userID":"42"}Route path:/user/:userID(\d+)
Request URL:http://localhost:3000/user/42
req.params:{"userID":"42"}
由于正则表达式通常是文字字符串的一部分,因此请确保\
使用其他反斜杠对所有字符进行转义,例如\\d+
。在Express4.x中,不以常规方式解释正则表达式中的*字符
路由处理程序
路由处理程序可以采用函数,函数数组或二者组合的形式
//回调数组,同时执行多个回调函数
var a = function(req,res,next){
console.log('a')
next()
}
var b = function(req,res,next){
console.log('b')
next()
}
var c = function(req,res,next){
console.log('c')
next()
}
app.get('/example/c',[a,b,c])
res
下表中相应对象()上的方法可以将响应发送到客户端,并终止请求-响应周期,如果没有从路由处理程序调用这些方法,则客户端请求将被挂起
方法 | 描述 |
---|---|
res.download() | 提示要下载的文件 |
res.end() | 结束响应过程 |
res.json() | 发送JSON相应 |
res.jsonp() | 发送带有JSONP支持的JSO相应 |
res.redirect() | 重定向请求 |
res.render() | 渲染视图模板 |
res.send() | 发送各种类型的相应 |
res.sendFile() | 将文件作为八位字节流发送 |
res.sendStatus() | 设置响应状态代码,并将其字符串表示形式发送为相应正文 |
app.route()
您可以使用来为路由路径创建可链接的路由处理程序app.route()
,由于路径是在单个位置指定的,因此创建模块化路由非常有帮助,减少冗余和错别字也很有帮助。
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")
})
快速路由器
在app目录中创建一个快速路由器
var express = require("express")
var router = express.Router()
router.use(function timeLog(req,res,next){
console.log("time:",Date.now())
next()
})
router.get("/",function(req,res){
res.send("Birds home page")
})
router.get('/about',function(req,res){
res.send("About birds")
})
module.exports = router
在应用程序中加载路由器模块
var birds = require('./birds')
app.use('/birds',birds)
暂无评论内容