这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
提到node就会想到express,刚开始在学习express还是有点艰难的,在b站找了很多课程看,从基础一步一步学起。
Express
一、介绍Express
Express有丰富的基础API支持,以及常见的HTTP辅助程序,例如重定向、缓存等;有强大的路由功能、灵活的中间件;高性能且稳定;Express仅仅提供了web开发的基础功能,它通过中间件的方法集成了许多外部插件来处理HTTP请求。
body-parser:解析HTTP请求体compression:压缩HTTP响应cookie-parser:解析cookie数据cors:处理跨域资源请求morgan:HTTP请求日志记录- ...
Express的中间件让Express本身变得更加灵活和简单,而缺点在于虽然有一些中间件包跨域解决几乎所有问题或需求,但是挑选合适的包有时也会成为一个挑战。Express不对Node.js已有的特性进行二次抽象,只是在它之上扩展了web应用所需要的基本功能;
- 内部使用的还是
HTTP模块 - 请求对象继承自:
http.IncomingMessage - 响应对象继承自:
http.ServerResponse
有很多流行框架基于Express,比如LoopBack、Sails、NextJs
Express的Hello World
引入express模块,创建一个服务器,再对浏览器的get请求做出响应;
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Hello World!'); // 发送响应
})
app.listen(3000);
二、路由基础
路由是指确定应用程序如何响应客户端对特定端点的请求,该特定端点是URI(或路径)和特定的HTTP请求方法(get,post等)。每个路由可以具有一个或多个处理程序函数,这些函数在匹配该路由时执行;采用下面的结构来实现:(如上面的get请求)
app.method(path, handle);
app是Express实例- method是小写的
HTTP请求方法 - path是服务器上的路径
- handle是当路由匹配执行的功能
请求和响应
Express应用使用路由回调函数的参数:request和response对象来处理对应的请求和响应的数据;
-
请求对象:获取请求相关的信息;继承自
http.IncomingMessage -
在express中可以通过
req.query获取请求参数 ;具体参考Express - API文档 -
响应对象:用来处理请求发送响应;继承自
http.ServerResponseres.cookie('foo', 'bar'); res.status(201).send({foo: 'bar'}); // 设置状态并响应
三、四种请求方式
我们在写每一个路由的时候,一般都要读取一些内容后对浏览器进行响应,比如说我们把数据放在db.json文件里面,然后再app.js文件中用fs.readFile()读取数据;这里可以把app.js中使用的一些使用频率高的方法写在另一个文件db.js里面,比如fs.readFiles()方法;
const fs = require('fs')
const { promisify } = require('util')
const path = require('path');
const readFile = promisify(fs.readFile);
const dbPath = path.join(__dirname, './db.json'); // 绝对路径
exports.getDb = async () => {
const data = await readFile(dbPath, 'utf-8');
return JSON.parse(data);
}
1. get请求
封装完之后在app.js中通过await getDb()就可以获取到对应的数据内容了;(记得async);如果不存在的话就返回404状态码,如果找到了就响应所找到的数据内容;用try...catch是为了避免一小部分错误导致整个程序无法运行;注意:req.params为请求参数
const { getDb } = require('./db')
app.get('/todos/:id', async (req, res) => {
try {
const db = await getDb();
const todo = db.todos.find(todo => todo.id === Number.parseInt(req.params.id));
if (!todo) { return res.status(404).end(); }
res.status(200).json(todo);
} catch (err) {
res.status(500).json({
error: err.message
})
}
})
2. post请求
-
配置解析表单请求体
application/json:app.use(express.json());将json形式的数据转为js对象;application/x-www-form-urlencoded:app.use(express.urlencoded) -
post我们一般用来提交数据,这里的话就要用到
fs.writeFile; -
同样地,把方法写在
db.js文件中;在写入数据的时候,我们如果想要让json中的数据看起来是有格式的话,以(db, null, ' ')为参数即可;exports.saveDb = async () => { const data = JSON.stringify(db, null, ' '); // 让db.json中的数据有格式 await writeFile(dbPath, data); } -
随后在
app.js对数据进行处理,如果todo.title不存在的话就返回404,如果存在的话就将添加的数据push到对应的数组(todo)中,数据提交后对数据进行写入处理;try { if (!todo.title) { return res.status(404).json({ error: 'The field title is required' }) } const db = await getDb(); const lastTodo = db.todos[db.todos.length - 1]; todo.id = lastTodo ? lastTodo.id + 1 : 1; db.todos.push(todo); await saveDb(db); res.status(200).json(todo); } catch (err) { res.status(500).json({ error: err.message }) }
3. patch请求
-
首先要通过
req.body获取表单数据:const todo = req.body; -
查找要修改的任务项,如果没有找到就说明不用改了,直接返回404即可;如果找到了就对这个数据进行修改,
const db = await getDb(); const ret = db.todos.find(todo => todo.id === Number.parseInt(req.params.id)); if (!res) { return res.status(404).end(); } Object.assign(ret, todo); await saveDb(db); res.status(200).json(ret);注意:
Object.assign方法是浅拷贝,第一个参数是目标对象,后面的参数都是源对象;如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性;
4. delete操作
-
找到要删除的项
const todoId = Number.parseInt(req.params.id); const db = await getDb(); const index = db.todos.findIndex(todo => todo.id === todoId); -
findIndex这个API查找返回索引,如果没找到就返回-1;找到后删除这个数据即可;if (index === -1) { return res.status(404).end(); } db.todos.splice(index, 1); await saveDb(db); res.status(200).end();
一直都挺好奇浏览器和服务器之间是怎么进行连接的,终于学到express了解到这个过程了