express框架中函数及内置中间件的使用

本文已发表于个人公众号:Rong姐姐好可爱,若仓库访问速度受限,可以直接访问公众号文章https://mp.weixin.qq.com/s/uo0xb60lZ_quxj8aPRPbKQ

express()函数

当你使用express框架的时候,一定会见过如下的引入:

const express=require('express')

跟koa框架中,引入koa到方式是一样的,例如:

const koa=require('koa')

而express官方提供express()函数来创建一个express应用;按照官方文档:

The express() function is a top-level function exported by the express module.

翻译:express()函数是express模块的顶级(最高级)函数的导出

express框架除了提供express()函数来创建一个express应用,也提供了一些内置方法:

  • express.json()
  • express.raw()
  • express.Router()
  • express.static()
  • express.text()
  • express.unlencoded()

一个个来讲解、整理吧~

express.json(options)

这是express框架内置的中间件函数,以body-parser为基础解析输入的请求为json格式;作为输入请求的解析器,支持body参数为Unicode的编码方式

当有接口请求过来时,会将body传递的参数,解析成一个object对象,可以通过req.body的方式进行获取;当出现以下情况,解析的对象会为空;

  • 没有以body的方式进行传参
  • content-type不匹配
  • 发生错误,没有执行解析的中间件

这里的body传参,可以了解下restful风格,其中请求类型为GET时,是不支持body传参的;

正如,body的参数结构是由用户控制的,对象中的所有属性和值是不可信的,在使用也就是信赖对象之前,需要先进行参数校验;

例如:在使用req.body.foot.toString()这段代码将出现错误;因为不通过校验,你不能确定用户在做接口请求的时候,一定会通过body来传递属性为foot的值,也有可能传递的不是string类型,这样的话,toString()方法调用也就没有意义了,所以强烈建议在使用之前进行参数校验

使用的时候,传递有效的参数

const express =require('express')
// 这里的options为属性组合的对象,支持对重属性定义;
const options={
    // inflate定义是否可能调整、压缩body参数对象,如果为false,调整body参数对象将会被拒绝,默认true,默认类型:Bloolean
    inflate:true, 
    // limit:控制请求体的最大容量,如果是数字,值将会被指定为数字的字节类型(100-->100byte),如果是字符串,将会依赖`bytes`库解析,按照kb、mb等方式解析,默认100kb,默认类型Mixed
    limit:'100kb',
    // revier:直接按照JSON.parse()解析为第二参数,默认为null,类型为Function
    reviver:null,
    // strict: 严格模式,是否允许只接受数组和对象作为参数,如果false将接受任何格式参数进行JSON.parse进行反序列化,获得对象,默认true,默认类型:Boolean
    strict:true,
    // type:请求数据的类型,可以参数content-type的设计,默认'application/json',默认类型Mixed
    type:'application/json',
    // verify: 当verify属性被应用时,将会以verify(req,res,buf,encoding)函数的方式,buf是原生request请求body参数的buffer结果,encoding是:request的编码,同样verify方法可能会执行失败,并且抛出错误异常 默认类型Funciton  默认值verify:undefined
}
// 使用json
express.json(options)

上面options的参数,可以充分自定义,没有特殊要求建议走默认

express.raw(options)

同样,express.raw()也是express框架的内置中间件,也是用来解析request请求体中body传参的,不过返回结果与
express.json()不同,这个中间件解析器将会返回buffer流,当Content-Type请求头类型匹配时只关注requests请求体;
和express.json()相同,接受任何类型的编码,并且能够自动进行gzip压缩;

使用的时候,传递有效的参数

const express =require('express')
// 这里的options为属性组合的对象,支持对重属性定义;
const options={
    // inflate定义是否可能调整、压缩body参数对象,如果为false,调整body参数对象将会被拒绝,默认true,默认类型:Bloolean
    inflate:true, 
    // limit:控制请求体的最大容量,如果是数字,值将会被指定为数字的字节类型(100-->100byte),如果是字符串,将会依赖`bytes`库解析,按照kb、mb等方式解析,默认100kb,默认类型Mixed
    limit:'100kb',
    // strict: 严格模式,是否允许只接受数组和对象作为参数,如果false将接受任何格式参数进行JSON.parse进行反序列化,获得对象,默认true,默认类型:Boolean
    strict:true,
    // type:请求数据的类型,可以参数content-type的设计,默认'application/json',默认类型Mixed
    type:'application/json',
    // verify: 当verify属性被应用时,将会以verify(req,res,buf,encoding)函数的方式,buf是原生request请求body参数的buffer结果,encoding是:request的编码,同样verify方法可能会执行失败,并且抛出错误异常 默认类型Funciton  默认值verify:undefined
}
// 使用json
express.raw(options)

可以看到express.raw(options)和express.json(options)的参数比较相似,功能也大同小异,相对来说,express.json(options)会用会多一些,建议根据api文档综合理解

express.Router(options)

注意,这里express.Router(options)中的Router是大写的,比较特殊;可能是为了区分touer路由吧。主要是用来创建一个新的路由对象

// 获取express模块的导入
const express=require('express')
const options={
    // caseSensitive: 是否大小写敏感,默认不敏感。即:路由'/Foot'与’/foot‘一致
    caseSensitive:false,
    // mergeParams;保护上级路由的路由参数req.params,如果父与子路由的路由参数冲突,子路由的params值将会优先  默认false
    mergeParams:false,
    // strict:是否支持路由严格模式,默认false。即:路由'/foot'与'/foot/'效果是一样的
    strict:false
}
// 定义路由对象
const router =express.Router(options)

当然,你也可以像application对象那样,在router中增加处理不同类型(get、post、delete、put等)的http请求的中间件

可以看到,express.Router(options)的options的属性在实际开发中用的比较少,严格区分路由,区分大小写这些无疑是增加了前后端对接和服务测试的成本,
可能你不会想到就可调用不成功,是路由大小写的问题;

express.static(root, [options])

最好的方式:通过使用反向代理缓存来提供服务端静态资源的访问;

express框架内置中间件函数,基于serve-static模块在服务端提供静态资源;
在express.static(root,options)中,第一个单数root是静态资源根目录地址。而函数本身则提供了通过url地址来访问服务端静态资源的方式(绑定),当文件不存在或者找不到时,将会返回404状态码,并不是调用next()函数在下一个中间件中处理 允许对目录进行渲染;

简单实例方式:


// 引入express 
const express=require('express')
// 创建应用入口
const app=express();
// 定义属性
const options = {
  // 决定文件或者目录是否从.(当前路径,相对地址)开始处理,默认类型:string,默认值:ignore
  dotfiles: 'ignore',
  // 是否产生实体标签(etag),默认值false,默认类型:Boolean
  etag: false,
  // 设置文件后缀,如果没有找到则搜索指定的后缀文件,默认false,默认类型Mixed
  extensions: ['htm', 'html'],
  // 
  index: false,
  maxAge: '1d',
  // 当路劲名是目录时,是否重定向到`/`目录中,默认值:true,默认类型:Boolean
  redirect: false,
  // 设置请求头
  setHeaders: function (res, path, stat) {
    res.set('x-timestamp', Date.now())
  }
}

// 简单使用
app.use(express.static('public', options))

注意,express.static(root,options),实质是一个中间件

express.text([options])

express框架内置中间件,借助body-parser将接口请求参数解析为字符串,并且返回中间件;当请求的请求头Content-Type满足匹配时,把body中所有参数解析成字符串,支持gzip压缩;

express.urlencoded([options])

这是Express中内置的中间件功能。它使用urlencoded有效负载分析传入请求,并基于body-parser
返回仅分析urlencoded主体的中间件,并仅查看Content-Type标题与type选项匹配的请求。该解析器只接受身体的UTF-8编码,并支持自动膨胀gzip和deflate编码。

body包含解析数据的新对象request在中间件(ie req.body)之后被填充到对象上,或者{}如果没有要解析的主体,Content-Type则不匹配或发生错误,则会填充空对象()。该对象将包含键-值对,其中该值可以是一个字符串或阵列(时extended是false),或任何类型的(当extended是true)。

  • extended

此选项允许选择使用查询字符串库(如果为false)或qs库(如果为true)解析URL编码数据。“扩展”语法允许将丰富的对象和数组编码为URL编码格式,从而允许使用URL编码的类似JSON的体验。有关更多信息,请参阅qs资料库。

默认类型:Boolean

默认值:true

  • inflate

启用或禁用处理放气(压缩)的物体; 当禁用时,放气的身体被拒绝。

默认类型:Boolean

默认值:true

  • limit

控制最大请求主体大小。如果这是一个数字,那么该值指定字节数; 如果它是一个字符串,则将该值传递给字节库以供解析。

默认类型:Mixed

默认值:“100kb”

  • parameterLimit

该选项控制URL编码数据中允许的最大参数数量。如果请求包含的参数多于此值,则会引发错误。

默认类型:Number

默认值:1000

  • type

这用于确定中间件将解析的媒体类型。该选项可以是字符串,字符串数组或函数。如果不是函数,则type选项将直接传递到type-is库,这可以是扩展名(如urlencoded),MIME类型(如application / x-www-form-urlencoded)或带MIME类型的MIME类型通配符(如* / x-www-form-urlencoded)。如果一个函数,类型选项被称为fn(req),并且如果它返回一个真值,则请求被解析。

默认类型:Mixed

默认值: “application/x-www-form-urlencoded”

  • verify

如果提供此选项,则称为verify(req,res,buf,encoding),其中buf是原始请求主体的缓冲区,编码是请求的编码。解析可以通过抛出错误来中止。

类型类型:Function

默认值:undefined

至此,express框架中,通过引入express模块,使用express()函数和中间件方法,可以局部或者全局处理路由请求,在开发中针对不同的需求合理的选择中间件,并配置好options对象参数;

参考资料

公众号

如果大家想要实时关注我更新的文章以及我的日常的话,可以关注我的公众号,基本每天都会更新技术和各种吹水文章,就当做是记录心情、成长的地方吧

<think>我们根据用户的要求,结合引用内容,来详细介绍Express框架中间件使用方法,包括具体示例和常见用法。引用[1][2][3]提到,Express官方将中间件分为5类:应用级别、路由级别、错误级别、内置中间件和第三方中间件。引用[4]特别说明了路由级别中间件是绑定在express.Router()实例上的。引用[5]展示了使用第三方中间件multer的示例。因此,我们将按照这5类中间件来组织回答,并给出具体示例。注意:在回答中,我们需要使用LaTeX格式的数学表达式(如果有的话)和代码示例,并按照要求添加引用标识。由于中间件本身不涉及太多数学公式,我们主要使用代码示例和文字说明。另外,按照用户要求,最后需要生成相关问题。</think>### Express 框架中间件使用指南 #### 一、中间件核心概念 中间件Express处理HTTP请求的核心机制,本质是**可链式调用的函数**,具有以下特性: - 访问请求对象(`req`)、响应对象(`res`)和流程控制函数(`next`) - 形成**请求处理流水线**:$$ \text{请求} \rightarrow \text{中间件}_1 \rightarrow \cdots \rightarrow \text{路由处理} \rightarrow \text{响应} $$ - 通过`next()`传递控制权,未调用将终止请求链[^1] #### 二、5类中间件详解(Express官方分类) ##### 1. 应用级别中间件 绑定到`app`实例,使用`app.use()`或`app.METHOD()`注册: ```javascript const express = require('express'); const app = express(); // 全局中间件(所有请求) app.use((req, res, next) => { console.log('全局中间件'); next(); }); // 路径限定中间件(仅匹配/api) app.use('/api', (req, res, next) => { req.apiRequestTime = Date.now(); next(); }); // 方法限定中间件(仅GET请求) app.get('/user', (req, res, next) => { console.log('用户GET请求中间件'); next(); }); ``` ##### 2. 路由级别中间件 绑定到`express.Router()`实例[^4]: ```javascript const router = express.Router(); // 路由专用中间件 router.use((req, res, next) => { console.log('路由中间件触发'); next(); }); router.get('/list', (req, res) => { res.send('用户列表'); }); // 挂载到应用 app.use('/users', router); ``` ##### 3. 错误处理中间件 **必须包含4个参数**,捕获前置中间件错误: ```javascript // 模拟错误抛出 app.get('/error', (req, res) => { throw new Error('测试错误'); }); // 错误处理(放在最后) app.use((err, req, res, next) => { console.error(err.stack); res.status(500).send('服务器错误'); }); ``` ##### 4. Express内置中间件 常用内置中间件: ```javascript // 静态文件服务 app.use(express.static('public')); // JSON请求体解析 app.use(express.json()); // URL编码解析 app.use(express.urlencoded({ extended: true })); ``` ##### 5. 第三方中间件 通过npm安装集成: ```javascript // 跨域支持 const cors = require('cors'); app.use(cors()); // 请求日志(示例:morgan) const morgan = require('morgan'); app.use(morgan('dev')); // 文件上传(示例:multer)[^5] const multer = require('multer'); const upload = multer({ dest: 'uploads/' }); app.post('/upload', upload.single('file'), (req, res) => { res.send(`文件已上传: ${req.file.filename}`); }); ``` #### 三、核心使用技巧 1. **执行顺序控制** ```javascript app.use((req, res, next) => { console.log('第一层'); // 先执行 next(); }); app.use((req, res, next) => { console.log('第二层'); // 后执行 next(); }); ``` 2. **修改请求/响应对象** ```javascript app.use((req, res, next) => { // 添加自定义属性 req.requestId = uuid.v4(); // 设置响应头 res.set('X-Powered-By', 'Express'); next(); }); ``` 3. **流程跳转** ```javascript // 条件跳过后续中间件 app.use('/admin', (req, res, next) => { if (!req.user.isAdmin) { return next('route'); // 跳过当前路由堆栈 } next(); }); ``` #### 四、最佳实践 1. **中间件组织原则** - 按功能分层:日志 → 安全 → 路由 → 错误处理 - 使用`router`模块化拆分路由 2. **推荐中间件组合** ```javascript // 典型中间件栈 app.use(helmet()); // 安全头部 app.use(compression()); // 响应压缩 app.use(cookieParser()); // Cookie解析 app.use('/api', apiRouter); // API路由 app.use(errorHandler); // 错误处理 ``` 3. **异步处理规范** ```javascript app.use(async (req, res, next) => { try { const data = await fetchData(); req.cachedData = data; next(); } catch (err) { next(err); // 错误传递 } }); ``` > Express中间件实现了**洋葱模型**处理流程,每个中间件像洋葱层一样包裹核心业务逻辑,这种设计显著提升了代码的可维护性和扩展性[^3]。 --- ### 常见问题解答 **Q:中间件执行顺序错误会导致什么?** A:典型问题包括: - 未解析请求体就访问`req.body`(需确保`express.json()`在路由前) - 错误处理中间件未放在最后(无法捕获前置错误) **Q:如何创建可配置中间件?** ```javascript // 带参数的中间件工厂 const logger = (format) => { return (req, res, next) => { console.log(`[${format}]: ${req.method} ${req.url}`); next(); } } app.use(logger('YYYY-MM-DD')); ``` 通过合理使用中间件,可构建高效、可维护的Express应用,处理复杂业务逻辑时能保持代码清晰度[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值