15158846557 在线咨询 在线咨询
15158846557 在线咨询
所在位置: 首页 > 营销资讯 > 网站运营 > Node.js——express开发web服务器

Node.js——express开发web服务器

时间:2023-05-25 04:09:02 | 来源:网站运营

时间:2023-05-25 04:09:02 来源:网站运营

Node.js——express开发web服务器:

一. Express初体验

1.1. 认识Web框架

前面我们已经学习了使用http内置模块来搭建Web服务器,为什么还要使用框架?

目前在Node中比较流行的Web服务器框架是express、koa;

express早于koa出现,并且在Node社区中迅速流行起来:

1.2. express的安装

express的使用过程有两种方式:

方式一:安装express-generator

npm install -g express-generator创建项目:

express express-demo项目目录如下:

├── app.js├── bin│ └── www├── package-lock.json├── package.json├── public│ ├── images│ ├── javascripts│ └── stylesheets│ └── style.css├── routes│ ├── index.js│ └── users.js└── views ├── error.jade ├── index.jade └── layout.jade我们可以安装依赖,将程序跑起来:

npm installnode bin/www方式二:从零学习搭建

刚才创建的项目express项目,很多内容可能我们并不认识,所以刚开始我们最好从零来学习。

初始化一个新的项目

npm init -yexpress的安装:

npm install express

1.3. express初体验

我们来创建自己的第一个express程序:

const express = require('express');// 创建服务器const app = express();// /home的get请求处理app.get("/home", (req, res) => { res.end("Hello Home");});// /login的post请求处理app.post("/login", (req, res) => { res.end("Hello Login");});// 开启监听app.listen(8000, () => { console.log("服务器启动成功~");})我们会发现,之后的开发过程中,可以方便的将请求进行分离:

当然,这只是初体验,接下来我们来探索更多的用法;

1.4. 请求和响应

请求的路径中如果有一些参数,可以这样表达:

返回数据,我们可以方便的使用json:

const express = require('express');const app = express();app.get('/users/:userId', (req, res, next) => { console.log(req.params.userId); res.json({username: "coderwhy", level: 99});});app.listen(8000, () => { console.log("静态服务器启动成功~");})

二. Express中间件

2.1. 认识中间件

Express是一个路由和中间件的Web框架,它本身的功能非常少:

中间件是什么呢?




中间件中可以执行哪些任务呢?

如果当前中间件功能没有结束请求-响应周期,则必须调用next()将控制权传递给下一个中间件功能,否则,请求将被挂起。

中间件函数调用的元素:







image-20201101205333843

2.2. 应用中间件

那么,如何将一个中间件应用到我们的应用程序中呢?

我们先来学习use的用法,因为methods的方式本质是use的特殊情况;

案例一:最普通的中间件

之所以称之为最普通的中间件,是因为无论是什么path、methods都会应用该中间件;

const express = require('express');const app = express();app.use((req, res, next) => { console.log("common middleware 01"); next();})app.use((req, res, next) => { console.log("common middleware 02"); res.end("Hello Common Middleware~");})app.listen(8000, () => { console.log("中间件服务器启动成功~");})中间件的执行顺序:

案例二:path匹配中间件

如果我们希望匹配一个明确的路径,也可以使用use方法:

// 案例二: 路径匹配中间件app.use('/home', (req, res, next) => { console.log("home middleware 01"); next();});app.use('/home', (req, res, next) => { console.log("home middleware 02"); next(); res.end("Hello Home middleware");});app.use((req, res, next) => { console.log("common middleware");});案例三:path和method匹配中间件

// 案例三: method匹配中间件app.get('/home', (req, res, next) => { console.log("home get middleware"); next();})app.post('/login', (req, res, next) => { console.log("login post middleware"); next();});app.use((req, res, next) => { console.log("common middleware");});案例四:注册多个中间件

// 案例四: 注册多个中间件const homeMiddleware1 = (req, res, next) => { console.log('home middleware 01'); next();}const homeMiddleware2 = (req, res, next) => { console.log('home middleware 02'); next();}const homeHandle = (req, res, next) => { res.end("Hello Home~");}app.get('/home', homeMiddleware1, homeMiddleware2, homeHandle);

2.3. 应用其他中间件

并非所有的中间件都需要我们从零去编写:

2.3.1. request解析中间件

在客户端发送post请求时,会将数据放到body中:

我们这里先使用json传递给服务器body:







json传递body

不进行解析时的操作:

app.post('/login', (req, res, next) => { req.on('data', (data) => { console.log(data.toString()); }) req.on('end', () => { res.end("登录成功~"); });});我们也可以自己编写中间件来解析JSON:

app.use((req, res, next) => { if (req.headers['content-type'] === 'application/json') { req.on('data', (data) => { const userInfo = JSON.parse(data.toString()); req.body = userInfo; }) req.on('end', () => { next(); }) } else { next(); }})app.post('/login', (req, res, next) => { console.log(req.body); res.end("登录成功~");});但是,事实上我们可以使用expres内置的中间件或者使用body-parser来完成:

app.use(express.json());app.post('/login', (req, res, next) => { console.log(req.body); res.end("登录成功~");});如果我们解析的是 application/x-www-form-urlencoded







form传递body

我们可以使用express自带的 urlencoded函数来作为中间件:




app.use(express.json());app.use(express.urlencoded({extended: true}));app.post('/login', (req, res, next) => { console.log(req.body); res.end("登录成功~");});

2.3.2. 日志记录中间件

如果我们希望将请求日志记录下来,那么可以使用express官网开发的第三方库:morgan

安装morgan:

npm install morgan直接作为中间件使用即可:

const loggerWriter = fs.createWriteStream('./log/access.log', { flags: 'a+'})app.use(morgan('combined', {stream: loggerWriter}));

2.3.3. 上传文件中间件

图片上传我们可以使用express官方开发的第三方库:multer

npm install multer上传文件,并且默认文件名:

const upload = multer({ dest: "uploads/"})app.post('/upload', upload.single('file'), (req, res, next) => { console.log(req.file.buffer); res.end("文件上传成功~");})添加文件名后缀:

const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, "uploads/") }, filename: (req, file, cb) => { cb(null, Date.now() + path.extname(file.originalname)); }})const upload = multer({ storage})app.post('/upload', upload.single('file'), (req, res, next) => { console.log(req.file.buffer); res.end("文件上传成功~");})我们也可以上传多张图片:

app.use('/upload', upload.array('files'), (req, res, next) => { console.log(req.files);});如果我们希望借助于multer帮助我们解析一些form-data中的普通数据,那么我们可以使用any:







image-20201104165039444

app.use(upload.any());app.use('/login', (req, res, next) => { console.log(req.body);});

2.4. 请求和响应

客户端传递到服务器参数的方法常见的是5种:

2.4.1. 请求解析

方式一:params

请求地址:http://localhost:8000/login/abc/why

获取参数:

app.use('/login/:id/:name', (req, res, next) => { console.log(req.params); res.json("请求成功~");})方式二:query

请求地址:http://localhost:8000/login?username=why&password=123

获取参数:

app.use('/login', (req, res, next) => { console.log(req.query); res.json("请求成功~");})

2.4.2. 响应方式

end方法

类似于http中的response.end方法,用法是一致的

res.end("Hello World");json方法

json方法中可以传入很多的类型:object、array、string、boolean、number、null等,它们会被转换成json格式返回;

res.json({name: "why", age: 18});status方法

用于设置状态码:

res.status(204);

三. 其他支持补充

3.1. 路由的使用

如果我们将所有的代码逻辑都写在app中,那么app会变得越来越复杂:




我们可以使用 express.Router来创建一个路由处理程序:

// 用户相关的处理const userRouter = express.Router();userRouter.get('/', (req, res, next) => { res.end("用户列表");});userRouter.post('/', (req, res, next) => { res.end("创建用户");});userRouter.delete('/', (req, res, next) => { res.end("删除用户");});app.use('/users', userRouter);当然,我们可以配置更多的路由,并且将所有的逻辑放到一个单独的文件中。

3.2. 静态资源服务器

部署静态资源我们可以选择很多方式:

const express = require('express');const app = express();app.use(express.static('./build'));app.listen(8000, () => { console.log("静态服务器启动成功~");})

3.3. 错误处理方式

app.use((req, res, next) => { next(new Error("USER DOES NOT EXISTS"));});app.use((err, req, res, next) => { const message = err.message; switch (message) { case "USER DOES NOT EXISTS": res.status(400).json({message}) } res.status(500)})

3.4. 源码分析

3.4.1. 创建app的过程

express函数的本质其实是createApplication







image-20201102161803339

当我们调用app.listen的时候,本质上是调用proto中的listen







image-20201102161939032

3.4.2. 注册中间件

比如我们通过use来注册一个中间件,源码中发生了什么?







image-20201102162627758

我们来看一下router.use中又做了什么事情?







image-20201102162749391

3.4.3. 请求的处理过程

如果有一个请求过来,那么从哪里开始呢?







image-20201102162943190

app.handle本质上会去调用router.handle:







image-20201102163035566

router.handle中做的什么事情呢?







image-20201102163153121








关键词:服务

74
73
25
news

版权所有© 亿企邦 1997-2025 保留一切法律许可权利。

为了最佳展示效果,本站不支持IE9及以下版本的浏览器,建议您使用谷歌Chrome浏览器。 点击下载Chrome浏览器
关闭