基于Node.js搭建express应用实现简单Web服务器功能
1. Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组强大的功能。2. Express 提供精简的基本 Web 应用程序功能,而不会隐藏 Node.js的功能。3. 许多流行的开发框架都基于Express 构建
从0搭建express应用结构
一、express基础
1、express简介
- Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组强大的功能。
- Express 提供精简的基本 Web 应用程序功能,而不会隐藏 Node.js的功能。
- 许多流行的开发框架都基于Express 构建
2、express安装
假设你已经安装过了node.js,你需要为你的express应用创建一个文件夹为接下来的操作准备。
-
npm init为express应用创建一个package.json文件,需要输入参数直接回车默认即可。json文件中会告诉你express依赖的其他包。
-
接下来在你新建的目录下安装 Express
npm install express --save并将其保存到依赖列表中,或者临时安装npm install express --no-save
二、中间件
1、什么是中间件
Express是一个路由和中间件的Web框架,它本身的功能非常少,Express的核心就是中间件。Express应用程序本质上可以理解为是一系列中间件函数的调用。
中间件的本质是传递给express的一个回调函数,这个回调函数接受三个参数
- ✨ 请求对象(request)
- ✨ 响应对象(response)
- ✨ next函数(用于执行下一个中间件的函数)
中间件可以干嘛呢?
- 🎉 执行任何代码
- 🎉 更改请求和响应对象
- 🎉 结束请求、响应周期(返回数据)
- 🎉 调用下一个中间件
如果匹配的第一个中间件没有结束请求-响应周期(没有调用res.end),则必须调用next将控制权传递给下一个中间件,不然请求将一直处于挂起状态
执行下列代码后在浏览中打开localhost:8089,服务器会打印出express体验成功,但是浏览器会一直处于加载中的状态
const express = require('express')
const app = express()
app.get('/', () => {
})
app.listen(8089, () => {
console.log('express体验成功')
})
2、编写普通中间件
express主要提供了两种方式编写中间件,本文选用app这种方式
- 🎄 app.use
- 🎄 router.use
这里用postman模拟客户端给服务器发送请求,对postman还不是很了解的可以看这篇文章,里面有简单描述postman的基础用法👉👉👉node.js+postman简单模拟HTTP服务器与客户端交互
服务器处理请求
const express = require('express')
// express本质是一个函数:createApplication
// 调用这个函数返回一个app,app本质上也是一个函数
const app = express()
// app.use注册的中间件(回调函数)可以被任意的http请求执行
app.use((req, res, next) => {
console.log('中间件1')
// res.end只是表示结束请求-响应的周期,并不影响next执行下一个中间件
res.end('welcome back')
// 执行完本中间件后继续查找执行能匹配的中间件
next()
})
// 客户端发送网络请求之后,每个中间件都能匹配到请求,但是只有第一个会响应
//如果没有next指向下一个中间件的话就只会执行第一个匹配的中间件
app.use((req, res, next) => {
console.log('中间件2')
})
app.use((req, res, next) => {
console.log('中间件3')
})
// 开启监听
app.listen(8089, () => {
console.log('express体验成功')
})
//express体验成功
//中间件1
//中间件2
3、编写path匹配中间件
在postman上模拟给服务器发送请求
服务器处理客户端(postman)发送的请求
const express = require('express')
const app = express()
//'/register'是接口用来判断中间件是否匹配
app.use('/register', (req, res, next) => {
console.log('我是1')
res.end('hollow路径匹配中间件1')
})
//只有和客户端发送请求时返回的接口一致中间件才会匹配执行
app.use('/login', (req, res, next) => {
console.log('我是2')
res.end('hollow路径匹配中间件2')
})
// 多个中间件只会执行匹配的第一个,除非有next会按next顺序执行
app.use('/login', (req, res, next) => {
console.log('我是3')
res.end('hollow路径匹配中间件3')
})
app.listen(8089, () => {
console.log('express体验成功')
})
//express体验成功
//我是2
4、编写methods匹配中间件
methods匹配中间件一样也主要有两种
- 🎄 app.methods
- 🎄 router.methods
其中methods指的是常用的http请求的方式,例如get或者post等
在postman上给localhost:8089/login发送get请求
服务器根据请求的路径和方法匹配适合的中间件
const express = require('express')
const app = express()
// 即使请求的路径和方法都与下面的app.get匹配,也会只执行第一个中间件(app.use可以被任何的http请求执行),除非有next指向下一个
// app.use((req, res, next) => {
// console.log('普通中间件')
// next()
// })
// 只有路径为/login,请求方法为get才能匹配成功
app.get('/login', (req, res, next) => {
console.log('get方法')
res.end('hollow get')
})
app.post('/login', (req, res, next) => {
console.log('post方法')
res.end('hollow post')
})
app.listen(8089, () => {
console.log('express体验成功')
})
//express体验成功
//get方法
四、数据解析
- 客户端发送get请求时一般会将数据放到url中传递给服务器,所以get请求传递的数据安全性和大小都有一定限制
- 客户端发送post请求时会将数据放到body中,客户端可以通过json的方式传递也可以通过application/x-www-form-urlencoded格式或者from-data格式传递
1、url解析
postman模拟客户端将数据通过url发送给服务器
服务器根据客户端的接口对url中的信息进行处理
const express = require('express')
const app = express()
// 相当于动态路由,后面的:id是根据客户端动态传过来的
// localhost:8089/products/apple/12
app.get("/products/:id/:neme", (req, res, next) => {
// 真实场景下可以通过url获取接口/products/后面的id,然后可以通过这个id去数据库里面查询商品数据,再通过res返回给客户端
//params方法可以对传递过来的url进行处理
console.log(req.params)
res.end("商品详情数据")
})
app.listen('8089', (req, res, next) => {
console.log("服务器开启成功")
})
//服务器开启成功
//{ id: 'apple', neme: '12' }
postman中可以直接预览query解析url后的参数
服务端对url中的数据进行解析
const express = require('express')
const app = express()
app.get("/login", (req, res, next) => {
console.log(req.query)
res.end("用户登录成功")
})
app.listen('8089', (req, res, next) => {
console.log("服务器开启成功")
})
// 服务器开启成功
//{ username: '阿花', password: 'ahua' }
2、json格式数据解析
postman以json格式给服务器传递数据
服务器对客户端的json数据进行解析
const express = require('express')
const app = express()
// 自己编写的node原生json解析
// app.use((req, res, next) => {
// if (req.headers["content-type"] === 'application/json') {
// // 提前对数据进行解析,然后传递给后面的中间件,免得每次调用中间件都要解析一次数据
// req.on('data', data => {
// // console.log(data.toString())
// const info = JSON.parse(data.toString())
// // console.log(info)
// // 相当于给req对象身上加了一个属性叫body
// req.body = info
// })
// req.on('end', () => {
// next()
// })
// } else {
// // next中不能传递参数,有错误的时候才会在next中传递参数
// next()
// }
// })
// express中的json方法解析
// json格式解析,解析后的结果放在了res.body属性中
app.use(express.json())
app.post('/login', (req, res, next) => {
console.log(req.body)
res.end('welcome to home~')
})
app.listen(8089, () => {
console.log('express体验成功')
})
//express体验成功
//{ username: '阿花', password: 'ahua' }
3、application/x-www-form-urlencoded数据解析
在postman中选中application/x-www-form-urlencoded格式,填写要给服务器传递的数据
服务器进行解析
const express = require('express')
const app = express()
// x-www-from-urlencoded格式解析
// false表明用node的内置模块querystring来解析
// true表示使用第三方库qs来解析
// urlencoded格式解析,解析后的结果放在了res.body属性中
app.use(express.urlencoded({ extended: true }))
app.post('/produces', (req, res, next) => {
console.log(req.body)
res.end('upload product info success~')
})
app.listen(8089, () => {
console.log('express体验成功')
})
4、from-data数据解析
express中没有直接对from-data格式数据进行解析的功能,但是可以利用官方库multer,可以去GitHub搜multer了解详细的信息。安装完成后便能实现对from-data数据的解析
用postman给服务器发送form-data格式数据
服务器解析
const express = require('express')
//导入multer
const multer = require('multer')
const app = express()
// 调用multer函数本质上是创建了一个对象
const upload = multer()
// 处理from-data类型一个只有文本域的表单,使用 .none():
app.use(upload.none())
app.post('/login', (req, res, next) => {
console.log(req.body)
res.end('用户登录成功')
})
app.listen(8089, () => {
console.log('from-data解析服务器')
})
//from-data解析服务器
//[Object: null prototype] { name: '阿花', id: 'ahua' }
5、文件上传
用postman给服务上传文件,这里我选择的是一张图片
服务器通过官方库multer对上传的文件进行解析
const path = require('path')
const express = require('express')
const multer = require('multer')
const app = express()
const storage = multer.diskStorage({
// 存储位置
destination: (req, fill, callback) => {
// 第一个参数表示有没有错误,第二个是路径
//如果没有这个文件夹,express会默认创建一个
callback(null, './uploads/')
},
// 文件名
filename: (req, fill, callback) => {
// 第一个参数表示有没有错误,第二个是文件名
//这样定义文件名可以防止客户端传递过来多个同名文件时发生的覆盖
// fill.originalname原始文件名
callback(null, Date.now() + path.extname(fill.originalname))
}
})
const upload = multer({
// 在multer中声明上传后文件存储的位置
//不自定义storage时服务器拿到的只是一个二进制文件
// dest: './uploads'
// 自定义存储信息,包括文件名,位置等
storage
})
//.any()可以接受一切上传的文件。文件数组将保存在 req.files。
// '/upload'是接口用来判断是否需要做文件上传
// upload.single(file)文件上传的中间件,从客户端获取到文件然后存放在指定位置,file是上传文件的key值,单个文件用single,多个文件用array
app.post('/upload', upload.single('file'), (req, res, next) => {
//单个保存在req.file中
console.log(req.file)
res.end('上传成功')
})
//多种文件用.any(),可以接受一切上传的文件。文件数组将保存在 req.files。
// 但是不能将upload.any()作为全局中间件(app.use(upload.any()))
// 因为用户会将数据传到一个预料不到的路由,所以应该只在需要处理文件的路由上使用
app.listen(8089, () => {
console.log('from-data文件上传')
})
在代码中将storage注释掉,打开 dest: './uploads',服务器解析到的会是标注的二进制文件

五、express路由
如果我们将所有的代码逻辑都写在app中,那么app会变得越来越复杂。一方面完整的Web服务器包含非常多的处理逻辑,另一方面有些处理逻辑其实是一个整体,我们应该将它们放在一起
比如对users相关的处理
- 获取用户列表;
- 获取某一个用户信息;
- 创建一个新的用户;
所以最好还是将他们放在单独的文件中,再引用进来即可
//user.js文件
const express = require('express')
const router = express.Router()
router.get('/', (req, res, next) => {
res.json(["xiaoming", "ahua", "tingting"])
res.end("获取用户列表")
})
router.get('/:id', (req, res, next) => {
res.json(`${req.params.id}用户信息`)
})
router.post('/', (req, res, next) => {
res.json("create user success~")
})
module.exports = router
//主文件
const express = require('express')
//导入user的路由
const UserRouter = require('./router/users')
const app = express()
app.use('/user', UserRouter)
app.listen(8089, (req, res, next) => {
console.log("路由服务器启动成功~")
})
文件目录
六、静态资源服务器
部署静态资源我们可以选择很多方式,node也可以作为静态资源服务器,并且express提供了很方便的部署方式。这里我放的是之前写的一个css的3d旋转相册,大家可以放自己的一些代码。

const express = require('express')
const app = express()
// 使用node原生的http方法需要去读取文件夹里面的文件然后再给客户端返回
// express里面使用中间件会自动找到文件夹把他作为静态服务器对应的文件夹
// 当请求静态资源的时候就会去这个文件夹里面找
app.use(express.static('./css-3d-imags/'))
app.listen('8089', () => {
console.log("静态服务器开启成功")
})
浏览器效果展示
七、利用 morgan库保存request日志
morgan也是express官方的库
const express = require('express')
const fs = require("fs")
const morgan = require("morgan")
const app = express()
//写入的位置,每次有新内容都会进行追加
const writeStream = fs.createWriteStream('./log/access.log', {
flags: "a+"
})
// combined用于决定打印的日志的保存格式
// stream: writeStream表示一旦有日志就会把日志写入到相应的某个位置
// 打印所有的日志可以用app.use()的全局中间件,也就是下面这种用法
// 只关注某一个接口的日志的话直接把中间件放到想关注的接口的中间的位置即可
app.use(morgan("combined", { stream: writeStream }))
app.get('/log', (req, res, next) => {
res.end("write log")
})
app.listen('8089', (req, res, next) => {
console.log('服务器启动成功')
})
目录结构
log中记录了每次发送请求的时间,请求方式,状态码以及请求来源
从零搭建express应用实现简单Web服务器功能基本就到这里了,如果有什么不妥当的欢迎指正🙋♂️🙋♀️
更多推荐
所有评论(0)