Node.js是一个基于Chrome V8引擎的Java Script运行环境。
一、初识Node.js
-
环境的安装
- 安装途径:
- 官网:https://nodejs.org/en/
- LTS版本是长期稳定版,建议安装
- 源码下载地址:https://nodejs.org/en/download/
- 历史版本下载地址:https://nodejs.org/dist/
- 官网:https://nodejs.org/en/
- 查看版本号:终端运行命令
node -v
如果能出现版本号,则证明安装成功。如果失败,注意Node.js安装目录是否添加到系统环境变量path中
- 安装途径:
-
执行js代码
- 在终端中执行:node 要执行的js文件路径
node E:\projects\my_test\test.js
- 在终端中执行:node 要执行的js文件路径
二、fs模块
fs 模块是Node.js 官方提供的、用来操作文件的模块。
-
读取文件
- 语法
fs.readFile(path[, options], callback)
- 参数
- 参数1:必选参数,字符串,表示文件的路径
- 参数2:可选参数,表示什么编码格式来读取文件,一般默认指定utf8
- 参数3:必选参数,文件读取完成后,通过回调函数拿到文件读取的结果
- 回调函数参数:
- 参数1:err,读取成功,err为null,否则返回错误对象,可以通过err.message获取失败信息
- 参数2:dataStr,成功读取的文件内容
- 回调函数参数:
- 示例
// 1、导入fs模块 const fs = require('fs') // 2、调用fs.readFile()方法读取文件 fs.readFile('./test.txt', 'utf8', (err, dataStr) => { //2.1 打印失败的结果 if(err){ return console.log('读取文件错误'+err.message) } //2.2 打印成功读取的结果 console.log('文件读取成功,内容:'+dataStr) })
- 语法
-
写入文件
- 语法
fs.writeFile(file, data[, options], callback)
- 参数
- 参数1:必选参数,需要指定一个文件路径的字符串,表示文件的存放路径
- 参数2:必选参数,表示要写入文件的内容
- 参数3:可选参数,表示以什么格式写入文件内容,默认值utf8
- 参数4:必选参数,文件写入完成后的回调函数
- 示例
// 1、导入fs模块 const fs = require('fs') // 2、调用fs.writeFile()方法写入文件 fs.writeFile('./test.txt', '通过writeFile方法写入的内容', (err) => { //2.1 打印失败的结果 if(err){ return console.log('写入文件错误'+err.message) } //2.2 打印成功的结果 console.log('文件写入成功') })
- 语法
-
路径动态拼接的问题
- 在使用fs模块操作文件时,如果使用 ./ 或者 ../ 开头的相对路径时,很容易会出现路径拼接错误的问题
- 原因:代码在运行的时候,会以执行 node 命令时所处的目录,动态拼接出被操作文件的完整路径
- 解决方案:
- 使用__dirname来拼接出完整路径
- __dirname:表示当前文件所处的目录
- 在使用fs模块操作文件时,如果使用 ./ 或者 ../ 开头的相对路径时,很容易会出现路径拼接错误的问题
三、path路径模块
path 模块是 Node.js 官方提供的、用来处理路径的模块。它提供了一系列的方法和属性,用来满足用户对路径的处理需求。
-
path.join([...paths])
- 路径拼接
- 参数:
- ...paths:路径片段的序列,字符串类型
-
path.basename(path[, ext])
- 获取路径中的文件名
- 参数:
- path:必选参数,表示一个路径的字符串
- ext:可选参数,表示文件扩展名
-
path.extname(path)
- 获取路径中的文件扩展名部分
- 参数:
- path:必选参数,表示一个路径的字符串
-
示例
const path = require('path') // 注意../会抵消前面的一层路径 fullPath = path.join('/a','b','../','c/index.html') console.log(fullPath) // a\c\index.html const fullName = path.basename(fullPath) console.log(fullName) // 输出 index.html const nameWithoutExt = path.basename(fullPath,'.html') console.log(nameWithoutExt) // 输出 index const extName = path.extname(fullPath) console.log(extName) // 输出 .html
四、http模块
http 模块是 Node.js 官方提供的、用来创建 web 服务器的模块。
-
创建基本的web服务器
const http = require('http') // 创建 web 服务器实例 const server = http.createServer() // 为服务器实例绑定 request 事件,监听客户端的请求 server.on('request', function (req, res) { const url = req.url const method = req.method const str = `Your request url is ${url}, and request method is ${method}` console.log(str) // 设置 Content-Type 响应头,解决中文乱码的问题 res.setHeader('Content-Type', 'text/html; charset=utf-8') // 向客户端响应内容 res.end(str) }) server.listen(8080, function () { console.log('server running at http://127.0.0.1:8080') })
-
根据不同的url响应不同的内容
const http = require('http') const server = http.createServer() server.on('request', (req, res) => { // 1.获取请求的url const url = req.url // 2.设置默认的响应内容为 404 Not found let content = '<h1>404 Not found!</h1>' // 3.判断用户请求的是否为 / 或 /index.html 首页 // 4.判断用户请求的是否为 /about.html 关于页面 if (url === '/' || url === '/index.html') { content = '<h1>首页</h1>' } else if (url === '/about.html') { content = '<h1>关于页面</h1>' } // 5.设置Content-Type响应头,防止中文乱码 res.setHeader('Content-Type', 'text/html; charset=utf-8') // 6.使用res.end()把内容响应给客户端 res.end(content) }) server.listen(80, () => { console.log('server running at http://127.0.0.1') })
五、模块化
-
模块化的基本概念
- 模块化是指解决一个复杂问题时,自顶向下逐层把系统划分为若干模块的过程。对于整个系统来说,模块是可组合、分解和更换的单元。
- 编程领域中的模块化,就是遵守固定的规则,把一个大文件拆成独立并互相依赖的多个小模块。
- 模块化可以提高代码的复用性、可维护性,可以实现按需加载。
-
模块的分类
- Node.js中根据模块来源的不同,将模块分为了3大类,分别是:
- 内置模块(由Node.js官方提供,例如fs、path、http等)
- 自定义模块(用户创建的每个js文件)
- 第三方模块(由第三方开发,使用前需要先下载)
- Node.js中根据模块来源的不同,将模块分为了3大类,分别是:
-
加载模块
- 使用强大的require()方法
// 1.加载内置的http模块 const http = require('http') // 2.加载用户自定义模块 const myUtils = require('./myUtils.js') // 3.加载第三方模块(需要先下载) const moment = require('moment')
注意:使用require()方法加载模块时,会执行被加载模块中的代码
- 使用强大的require()方法
-
模块作用域
- 和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域
- 好处:
- 防止了全局变量污染的问题
-
向外共享模块作用域中的成员
- module对象
- 在每个.js自定义模块中都有一个module对象,它里面存储了和当前模块有关的信息
- module.exports对象
- 在自定义模块中,可以使用module.exports对象,将模块内的成员共享出去,供外界使用
- 外界使用require()方法导入自定义模块时,得到的就是module.exports所指向的对象
- 默认情况下,module.exports = {}
- exports对象:
- 默认情况下,exports和module.exports指向同一个对象。最终共享的结果,还是以module.exports指向的对象为准
- module对象
-
模块化规范
- Node.js遵循了CommonJS模块化规范,CommonJS规定了模块的特性和各模块之间如何相互依赖
- CommonJS规定:
- 每个模块内部,module 变量代表当前模块
- moudle 变量是一个对象,它的exports属性(即module.exports
)
是对外的接口 - 加载某个模块,其实是加载该模块的module.exports 属性。require()方法用于加载模块
-
模块的加载机制
- 优先从缓存中加载
- 模块在第一次加载后会被缓存。这也意味着多次调用require()不会导致模块的代码被执行多次,从而提高模块的加载效率
- 内置模块的加载机制
- 内置模块的加载优先级最高
- 例如,加载fs模块时,即使node_modules目录下有同名的包,也会返回内置的fs模块
- 内置模块的加载优先级最高
- 自定义模块的加载机制
- 必须指定以 ./ 或 ../ 开头的路径标识符,否则会当作内置模块或第三方模块进行加载
- 在使用require()导入自定义模块时,如果省略了文件的扩展名,则Node.js会尝试按照顺序加载以下的文件:
- 按照确切的文件名进行加载
- 补全.js扩展名进行加载
- 补全.json扩展名进行加载
- 补全.node扩展名进行加载
- 加载失败,终端报错
- 第三方模块的加载机制
- 如果传递给require()的模块标识符不是一个内置模块,也不是以 ./ 或 ../ 开头,则Node.js会从当前模块的父目录开始,尝试从/node_modules文件夹中加载第三方模块。
- 如果没有找到对应的第三方模块,则去上一层父目录中进行加载,直到文件系统的根目录
- 例如,假设在 C:\Users\bruce\project\foo.js 文件里调用了 require('tools'),则 Node.js 会按以下顺序查找:
- C:\Users\bruce\project\node_modules\tools
- C:\Users\bruce\node_modules\tools
- C:\Users\node_modules\tools
- C:\node_modules\tools
- 报错
- 目录作为模块
- 当把目录作为模块标识符,传递给require()进行加载的时候,有三种加载方式:
- 在被加载的目录下查找一个叫做package.json的文件,并寻找main属性,作为require()加载的入口
- 如果目录里没有package.json文件,或者main入口不存在或无法解析,则Node.js将会试图加载目录下的index.js文件
- 以上均失败,则终端报错
- 当把目录作为模块标识符,传递给require()进行加载的时候,有三种加载方式:
- 优先从缓存中加载
六、npm与包
-
包
- Node.js中的第三方模块又叫做包
- 不同于内置模块和自定义模块,包是由第三方个人或团队开发出来的,免费供所有人使用。
- 包是基于内置模块封装出来的,提供了更高级、更方便的API,极大的提高了开发效率
- 搜索包网站:https://www.npmjs.com/
- 下载包地址:https://registry.npmjs.org/
-
npm
- Node Package Manager(简称npm包管理工具),随着Node.js的安装包一起安装到用户电脑上,使用这个包管理工具,可以从https://registry.npmjs.org/服务器将需要的包下载到本地使用
- 终端执行 npm -v 命令,可以查看npm包管理工具的版本号
npm -v
- 初次安装包以后多了哪些文件?
- node_modules文件夹:用来存放所有已安装到项目中的包。require()导入第三方包时,就是从这个目录中查找并加载包
- package-lock.json配置文件:用来记录node_modules目录下的每一个包的下载信息,例如包的名字、版本号、下载地址等
- 注意:
- 上述文件夹和文件中的内容我们不需要手动维护,由npm自动维护
- 安装包
- npm install 包名
- 也可简写为:npm i 包名
- npm install 包@版本号
- 指定版本安装
npm install [email protected]
第1位数字2表示大版本,第2位数字29表示功能版本,第3位数字4表示Bug修复版本,只要前面的版本号增长了,后面的版本号就需要归零
- 指定版本安装
- npm install 包名
- 包管理配置文件
- 在项目根目录中,必须提供一个叫做package.json的包管理配置文件,即可用来记录项目中安装了哪些包。
- 多人协作开发时,为了避免第三方包的体积过大,在团队成员间共享项目源代码时,需要剔除node_modules目录
- 注意:
- 在项目开发中,一定要把node_modules文件夹,添加到.gitignore忽略文件中
- 注意:
- 快速创建package.json
- 在项目根目录下,执行下述命令
npm init -y
建议在新建项目以后,不要急于写代码,而是首先执行上述命令创建包管理配置文件
- 注意:
- 上述命令只能在英文目录下成功运行,项目文件夹名不要使用中文,不能出现空格
- 运行npm install命令安装包的时候,npm包管理工具会自动把包的名称和版本号记录到package.json中
- 在项目根目录下,执行下述命令
- dependencies节点
- package.json文件中,有一个dependencies节点,专门用来记录使用npm install命令安装了哪些包
- 一次性安装所有包
- 可以运行npm install命令(或npm i)一次性安装所有依赖包
// 执行npm install命令时,npm包管理工具会先读取package.json中的dependencies节点,依次将相应版本号的包下载到项目中 npm install
- 可以运行npm install命令(或npm i)一次性安装所有依赖包
- 卸载包
- 可以运行npm uninstall命令来卸载指定包
npm uninstall moment
执行命令后,自动把卸载的包从package.json中的dependencies节点中移除
- 可以运行npm uninstall命令来卸载指定包
- devDependencies节点
- 只在项目开发阶段会用到,而项目上线后不会用到的包,建议安装到devDependencies节点中
- 使用如下命令,会将包记录到devDependencies节点
npm i 包名 -D // 上述命令是简写形式,等价于:npm i 包名 --save-dev
- 解决包下载速度慢的问题
- 使用淘宝NPM镜像服务器
// 查看当前的下包镜像源 npm config get registry // 将下包镜像源切换为淘宝镜像源 npm config set registry=https://registry.npm.taobao.org/ // 检查下包镜像源是否切换成功 npm config get registry
- nrm
- 为了更方便的切换下包镜像源,可以安装nrm这个小工具,利用nrm提供的终端命令来查看和切换下包镜像源
// 全局安装nrm npm install nrm -g //查看所有可用的镜像源 nrm ls // 将镜像源切换为taobao nrm use taobao
注意:安装nrm需要以管理员身份运行终端
- 为了更方便的切换下包镜像源,可以安装nrm这个小工具,利用nrm提供的终端命令来查看和切换下包镜像源
- 使用淘宝NPM镜像服务器
- 包的分类
- 项目包
- 那些被安装到项目的node_modules目录中的包,都是项目包
- 项目包又分为两大类:
- 开发依赖包(被记录到devDependencies节点中的包,只在开发期间会用到)
- 核心依赖包(被记录到Dependencies节点中的包,在开发和项目上线之后都会用到)
npm i 包名 -D // 开发依赖包 npm i 包名 // 核心依赖包
- 全局包
- 在执行npm install命令时,如果提供了 -g 参数,则会把包安装为全局包
- 全局包会被安装到C:\Users\用户目录\AppData\Roaming\npm\node_modules目录下
- 项目包
- 规范的包结构
- 一个规范的包,它的组成解构,必须符合以下3点要求:
- 包必须以单独的目录而存在
- 包的顶级目录下必须包含package.json这个包管理配置文件
- package.json中必须包含name, version, main这三个属性,分别代表:包的名字、版本号、包的入口
- 一个规范的包,它的组成解构,必须符合以下3点要求:
七、Express
Express是基于Node.js平台,快速、开放、极简的Web开发框架
-
安装
npm install express
在项目所处的目录中,运行终端命令,即可将express安装到项目中使用
-
nodemon
- nodemon这个工具,能够监听项目文件的变动,当代码被修改后,nodemon会自动帮我们重启项目,极大方便了开发和调试
- 安装
- 终端中执行如下命令,进行全局安装
npm install nodemon -g
- 终端中执行如下命令,进行全局安装
- 使用
- 将传统的node命令替换为nodemon命令即可,例如启动test.js
nodemon test.js
注意:安装nodemon后需要以管理员身份运行终端
- 将传统的node命令替换为nodemon命令即可,例如启动test.js
-
创建基本的Web服务器
// 1、导入express const express = require('express') // 2、创建Web服务器 const app = express() // 3、调用app.listen(端口号,启动成功后的回调函数)启动服务器 app.listen(8080, () => { console.log('Express server running at http://127.0.0.1:8080') })
-
监听GET和POST请求
-
- 语法
// 监听GET请求 app.get('请求url', function(req, res){/*处理函数*/}) //监听POST请求 app.post('请求url', function(req, res){/*处理函数*/})
- 参数
- 参数1:客户端请求的url地址
- 参数2:请求对应的处理函数
- req:请求对象(包含了请求相关的属性和方法)
- req.query:获取客户端发送过来的查询参数,默认是空对象{}
- req.params:获取动态匹配到的url参数,默认是空对象{}
- req.body:接收客户端发送过来的请求体数据,如果不配置解析表单数据的中间件,默认等于undefined
- res:响应对象(包含了与响应相关的属性与方法)
- res.send()方法:响应内容给客户端
- req:请求对象(包含了请求相关的属性和方法)
-
-
-
- 可以响应JSON对象
- 也可以响应字符串
-
-
- 示例
// 导入express const express = require('express') // 创建Web服务器 const app = express() app.get('/user',(req, res) => { // 调用res.send()方法,向客户端响应一个JSON对象 res.send({name: '张三', age: 20, gender: '男'}) }) app.post('/user', (req, res) => { // 调用res.send()方法,向客户端响应一个文本字符串 res.send('请求成功') }) app.get('/',(req, res) => { // 通过 req.query 可以获取到客户端发送过来的查询参数,默认是一个空对象{} console.log(req.query) res.send(req.query) }) // 注意:这里的id和username是动态参数,格式':参数名' app.get('/user/:id/:username',(req, res) => { // 通过 req.params 动态匹配到的url参数,默认情况下是一个空对象{} console.log(req.params) res.send(req.params) }) // 调用app.listen(端口号,启动成功后的回调函数)启动服务器 app.listen(8080, () => { console.log('Express server running at http://127.0.0.1:8080') })
- 语法
-
托管静态资源
- 通过express.static()函数可以非常方便地创建一个静态资源服务器,在指定的静态目录中查找文件,并对外提供资源的访问路径
- 托管多个静态资源目录,需要多次调用express.static()函数,会根据目录添加的顺序查找所需文件
- 在托管的静态资源访问路径之前,可以挂载路径前缀
// 导入express const express = require('express') // 创建Web服务器 const app = express() // 调用express.static()方法,快速对外提供静态资源 // 优先查找public目录,其次查找files目录 app.use(express.static('./public')) app.use(express.static('./files')) // 挂载路径前缀 // 通过带有/public前缀来访问public目录中的文件 app.use('/public',express.static('./public')) app.listen(8080, () => { console.log('express server running at http://127.0.0.1:8080') })
-
路由
- 为了方便对路由进行模块化管理,不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块
- 将路由抽离为单独模块的步骤:
- 创建路由模块对应的js文件
- 调用express.Router()函数创建路由对象
- 向路由对象上挂载具体的路由
- 使用module.exports向外共享路由对象
- 使用app.use()函数注册路由模块
- 创建路由模块
// 路由模块 router.js // 1、导入express const express = require('express') // 2、创建路由对象 const router = express.Router() // 3、挂载具体的路由 router.get('/user/list', (req, res) => { res.send('Get user list.') }) router.post('/user/add', (req, res) => { res.send('Add new user.') }) // 4、向外暴露路由对象 module.exports = router
- 注册路由模块
const express = require('express') const app = express() // 1、导入路由模块 const router = require('./router.js') // 2、注册路由模块,并添加统一的访问前缀 /api app.use('/api',router) // 注意: app.use()函数的作用,就是注册全局中间件 app.listen(8080, () => { console.log('express server running at http://127.0.0.1:8080') })
-
中间件
- 概念
- 中间件(Middleware),特指业务流程的中间处理环节
- 当请求到达Express的服务器之后,可以连续调用多个中间件,从而对这次请求进行预处理
- Express的中间件,本质上就是一个function处理函数,形参包含req、res和next
- next()函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
- 多个中间件之间共享同一份 req 和 res。基于这个特性,可以在上游的中间件中,统一为 req 或 res 对象添加自定义的属性或方法,供下游的中间件或路由进行使用
- 可以使用app.use()
- 全局生效的中间件
- 客户端发起的任何请求到达服务器之后,都会触发的中间件,叫做全局生效的中间件
- 通过调用app.use(中间件函数),即可定义一个全局生效的中间件
- 可以使用app.use()连续定义多个全局中间件,当客户端请求到达服务器之后,会按照中间件定义的先后顺序依次进行调用
const express = require('express') const app = express() // 定义第一个全局中间件 app.use((req, res, next) => { console.log('调用了第一个全局中间件') next() }) // 定义第二个全局中间件 app.use((req, res, next) => { console.log('调用了第二个全局中间件') next() }) // 定义路由 app.get('/user', (req, res) => { console.log('调用了 /user 这个路由') res.send('User Page.') }) app.listen(8080, () => { console.log('express server running at http://127.0.0.1:8080') })
- 局部生效的中间件
- 不用app.use()定义的中间件,叫做局部生效的中间件
const express = require('express') const app = express() // 1、定义中间件函数 const mw1 = function(req, res, next){ console.log('调用了局部生效的中间件') next() } // 2、定义路由 // mw1 这个中间件,只在'当前路由中生效',这种用法属于'局部生效的中间件' app.get('/', mw1, (req, res) => { res.send('Home Page.') }) app.get('/user', (req, res) => { res.send('User Page.') }) app.listen(8080, () => { console.log('express server running at http://127.0.0.1:8080') })
- 可以在路由中,通过如下两种等价的方式,使用多个局部中间件:
// 以下两种方法完全等价,根据喜好选择任意一种 // 第一个参数是路径url // 最后一个参数是处理函数 // 中间可以是任意多个中间件 app.use('/', mw1, mw2, (req, res) => {req.send('Home Page.')}) app.use('/', [mw1, mw2], (req, res) => {req.send('Home Page.')})
- 不用app.use()定义的中间件,叫做局部生效的中间件
- 中间件使用注意事项
- 一定要在路由之前注册中间件
- 客户端发送过来的请求,可以连续调用多个中间件进行处理
- 执行完中间件的业务代码之后,不要忘记调用next()函数
- 为了防止代码逻辑混乱,调用next()函数后不要再写额外代码
- 连续调用多个中间件时,多个中间件之间共享 req 和 res 对象
- 中间件分类
- 应用级别的中间件
- 通过app.use()或app.get()或app.post()绑定到app实例上的中间件,叫做应用级别的中间件
- 路由级别的中间件
- 绑定到express.Router()实例上的中间件,叫做路由级别的中间件,它的用法和应用级别的中间件没有任何区别,只不过一个绑定到app实例上,一个绑定到router实例上
- 错误级别的中间件
- 专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
- 错误级别中间件的 function 处理函数中,必须有4个形参,先后顺序分别是(err, req, res, next)
- 错误级别的中间件,必须注册在所有路由之后
const express = require('express') const app = express() // 1、定义路由 app.get('/', (req, res) => { // 人为抛出异常 throw new Error('服务器的内部发生了错误!') res.send('Home Page.') }) // 2、定义错误级别的中间件,捕获整个项目的异常错误,从而防止程序的崩溃 app.use((err, req, res, next) => { console.log('捕获了异常:'+err.message) res.send('Error!'+ err.message) }) app.listen(8080, () => { console.log('express server running at http://127.0.0.1:8080') })
- Express内置的中间件
- 自Express 4.16.0版本开始,Express内置了3个常用的中间件,极大提高了Express项目开发的效率和体验:
- express.static 快速托管静态资源的内置中间件,例如HTML文件、图片、CSS样式等(无兼容性问题)
- express.json 解析JSON格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
- express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在4.16.0+版本中可用)
const express = require('express') const app = express() // 除了错误级别的中间件,其他的中间件必须在路由之前进行配置 // 通过express.json()这个中间件,解析表单中的JSON格式数据 app.use(express.json()) // 通过express.urlencoded()这个中间件,解析表单中的url-encoded格式的数据 app.use(express.urlencoded({extended: false})) // 创建路由 app.post('/user', (req, res) => { // req.body可以获取JSON格式的表单数据和url-encoded格式的数据 // 不配置任何解析表单的中间件,req.body默认等于 undefined console.log(req.body) res.send(req.body) }) // 指定端口号,并启动服务器 app.listen(8080, () => { console.log('express server running at http://127.0.0.1:8080') })
- 自Express 4.16.0版本开始,Express内置了3个常用的中间件,极大提高了Express项目开发的效率和体验:
- 第三方的中间件
- 由第三方开发出来的中间件,叫做第三方中间件
- 在项目中,可以按需下载并配置第三方中间件,从而提高项目的开发效率
- 在[email protected]之前的版本中,经常使用 body-parser 这个第三方中间件来解析请求体数据,步骤:
- 运行 npm install body-parser 安装中间件
- 使用require导入中间件
- 调用app.use()注册并使用中间件
const express = require('express') const app = express() // 导入表单解析中间件 body-parser const parser = require('body-parser') // 使用app.use()注册中间件 app.use(parser.urlencoded({extended: false})) // 内置的express.urlencoded中间件,就是基于body-parser这个第三方中间件进一步封装出来的 // app.use(express.urlencoded({extended: false})) // 创建路由 app.post('/user', (req, res) => { // req.body可以获取JSON格式的表单数据和url-encoded格式的数据 // 不配置解析表单的中间件,req.body默认等于 undefined console.log(req.body) res.send(req.body) }) // 指定端口号,并启动服务器 app.listen(8080, () => { console.log('express server running at http://127.0.0.1:8080') })
- 应用级别的中间件
- 概念