express基础笔记


项目搭建

简单的入门步骤: hello world!

  1. 创建一个项目文件夹
mkdir express-demo
  1. 进入文件夹
cd express-demo
  1. 在文件夹中创建自己的模块文件夹并进入
  2. 生成package.json文件
npm init -y
  1. 安装express
npm i express
  1. 创建入口文件 app.js 在该文件中创建web 服务
touch app.js
  1. 在app.js中书写基本的web请求
const express = require('express');
const app = express();
//'/'表示根目录
//运行之后访问http://localhost:3000
app.get('/', (req, res) => {
    res.send("get请求成功")
})

app.post('/', (req, res) => {
    res.send("post请求")
})
//运行之后访问http://localhost:3000/user
app.put('/user', (req, res) => {
    res.send('put express')
})

app.delete('/user', (req, res) => {
    res.send('delete express');
})
//3000表示请求的端口号 
app.listen(3000,() => {
	console.log('Server running');
})
  1. 运行app.js(命令行要在对应文件所在目录输入);运行之后,打开对应的网页即可看到get方法中res.send中的内容;
    因为浏览器地址栏只能发送get请求,如果想要测试post请求,可以借助postman工具postman官网
node app.js

如果不想要每次修改都运行一遍node app.js 可以安装nodemon工具

npm install nodemon

运行之后每次保存都会重新刷新

nodemon app.js

因为环境的差异,有的运行上面的代码会报错.可以尝试运行

npx nodemon app.js

提示:以下是本篇文章正文内容,下面案例可供参考

一、express路由基础

一个路由由 请求方法 请求路劲 回调函数组成

路由是指确定应用程序如何相应客户端对特定端点的请求,该特定端点是URL(或路径)和特定的HTTP请求方法(GET,POST等).
每个路由可以具有一个或多个处理程序函数,这些函数在匹配该路由时执行.

var http = require('http')
// 通过http模块 创建web应用
var app = http.createServer((req,res) => {
    res.writeHead(200,{"ContentType":"text/plain"})//状态码,返回格式
    res.end('Hello World');//结束响应同时 发送数据
})

// 通过监听端口启动
app.listen(3000,'localhost')
console.log('http://localhost:3000');

上面的这段代码和下面这段代码 app.get('/',function())效果相同

//req 请求对象 
//res 响应对象
app.get('/', (req, res) => {
    res.send("get请求成功")
})

二、请求和响应

expres使用路由回调函数的参数:request 和 response对象来处理请求和响应的数据.
express不对node.js已有的特征进行二次抽象,只是在它基础上扩展了web应用的基本功能;内部使用还是http 感兴趣可以查看nodejs官方文档中的Class: http.IncomingMessage部分
更多请求相关参数 请访问express官方文档

(一) 响应对象

res对象 表示express在收到http请求时发送的http响应.
继承于nodejs中的Class: http.ServerResponse;

原生响应

  • res.statusCode = 500
  • res.statusMessage = ‘mess’
  • res.setHeader(‘aa’,‘bb’)
  • res.write(‘hello world’)
  • res.end(‘end’)

express响应

  • res.status(500)
  • res.set(‘aa’,‘bb’)
  • res.send(‘你好 美丽的姑娘’)

跳转响应 res.redirect(‘http://baidu.com’)
下载响应 res.download(__dirname + ’ /app.json’)
json响应 res.json({ name:‘魔法’ })
响应文件内容 res.sendFile(__dirname + ’ /test.html ')

(二)状态码

  • 1xx: 相关信息
  • 2xx: 操作成功
  • 3xx: 重定向
  • 4xx:客户端错误
  • 5xx:服务器错误

三、express基本用法

为方便理解,数据采用json文件保存,没有连接数据库

在app.js的同级目录下,创建一个db.json文件;
内部写入json格式的数据.示例如下:

{
  "todos": [
    {
      "id": 1,
      "title": "run"
    },
    {
      "id": 2,
      "title": "play"
    },
    {
      "id": 3,
      "title": "eat"
    }
  ],
  "user": []
}

(一)查询数据列表

在app.js中引入fs文件处理模块

const fs = require('fs')

通过**fs.readFile()**方法异步读取文件,具体步骤如下:

app.get('/todos', (req, res) => {
    // 异步读取文件 (读取的文件,文件编码,回调函数)
    fs.readFile('./db.json', 'utf-8', (err, data) => {
        if (err) {
            return res.status(500).json({
                // 发送500错误代码,以json数据发送
                error: err.message
            })
        }
        const db = JSON.parse(data)
        // 响应状态码
        res.status(200).json(db.todos)
    })
})

运行结果如下:
在这里插入图片描述

(二)根据id查询单个数据

	通过app.get('/',()=>{})可以配置路由
	/:id  表示请求参数是id
	req.params.id 获取路由中的参数
	find() 方法 查找文件内容
	Number.parseInt() 将字符串转为int类型

具体操作步骤如下代码.返回的结果是id为1的数据

// 根据id查询单个任务
app.get('/todos/:id', (req, res) => {
    fs.readFile('./db.json', 'utf-8', (err, data) => {
        if (err) {
            return res.status(500).json({
                error: err.message
            })
        }
        const db = JSON.parse(data)
        const todo = db.todos.find(todo => todo.id === Number.parseInt(req.params.id));
        if (!todo) {
            res.status(404).end();//响应状态码
            return
        }
        res.status(200).json(todo)
    })
})

(三) 封装查询

为了减少代码的冗余,增加代码的可读性,可以将请求数据的方法封装到单独文件.
在app.js同级 创建一个db.js文件

	将回调函数转换为异步方法
	const { promisify } = require('util')
	
	node 提供的用于处理文件和目录的路径的实用工具
	const path = require('path')
	
	path.join() 路径拼接
	__dirname 用来动态获取当前文件所属目录的绝对路径
	__filename 用来动态获取当前文件的绝对路径,包含当前文件

	JSON.parse() 方法将数据转换为 JavaScript 对象。

具体代码实现如下

const fs = require('fs')
const { promisify } = require('util') //将callback转为promis类方法
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)
}

封装之后需要在头部进行引用,封装的时候因为没有回调函数处理异常,所以在调用的时候需要使用try{}catch{}对异常进行捕获.

因为readFile()被转换成promise 所以需要在方法前加上async 采用异步方式调用

const { getDb } = require('./db');
//查询全部数据
app.get('/todos', async (req, res) => {
    try {
        const todo = await getDb()
        res.status(200).json(todo.todos)
    } catch (err) {
        res.status(500).json({
            error: err.message
        })
    }
 })
//根据id查询
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
        })
    }
})

(四) 数据添加

	使用Postman进行数据请求;
	1.获取请求体
		req.body
		在获取请求体之前 需要配置解析表单请求体
		const express = require('express')
		const app = express();
		//解析:application/json
		app.use(express.json());
		//解析:application/x-www-form-urlencoded
		app.use(express.urlencoded());
	2.验证请求体
	3.请求体写入json文件
		push()
		JSON.stringify() 将js对象转换为字符串
		writeFile(file,data);
	4.返回响应数据

演示代码如下:

  1. 写入方法封装
// 写入数据
const writeFile = promisify(fs.writeFile)

exports.saveDb = async (db) => {
    const data = JSON.stringify(db);//JSON.stringify() 方法将 JavaScript 对象转换为字符串。
    // const data = JSON.stringify(db,null,'  ');//带格式的写入方式
    await writeFile(dbPath, data);
}
  1. 配置解析和postman请求演示

配置对应的请求方式
3. 代码请求

app.post('/todos', async (req, res) => {
  try {
    // 1.获取客户端请求体参数
    const todo = req.body
    // 2.数据验证
    if (!todo.title) {
      return res.status(422).json({
        error: 'The field title is required'
      })
    }
    // 3.存储数据
    const db = await getDb();
    const lastId = db.todos[db.todos.length - 1];
    todo.id = lastId ? lastId.id + 1 : 1;

    db.todos.push(todo)
    await saveDb(db);
    // 4.成功响应
    res.status(201).json(todo);
  } catch (err) {
    res.status(500).json({
      error: err.message
    })
  }
})

(五)数据修改

Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
注意:如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

	1.获取表单数据
	2.查找到要修改的数据
	3.数据组装/数据合并 将2合并到1中
	Object.assign(ret1,ret2)
	4.数据写入
	5.返回响应数据

总体逻辑和写入相似,调用的方法也是写入的方法,代码示例如下

app.patch('/todos/:id', async (req, res) => {
  try {
    const ret = req.body;
    const db = await getDb()
    const todo_id = db.todos.find(todo => todo.id === Number.parseInt(req.params.id))

    if (!todo_id) {
      return res.status(404).end()
    }

    Object.assign(todo_id, ret)
    await saveDb(db);

    res.status(200).json(ret)
  } catch (err) {
    res.status(500).json({
      error: err.message
    })
  }
})

(六) 数据删除

splice(index,number) 方法用于添加或删除数组中的元素。返回删除的数组
findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
findIndex() 方法为数组中的每个元素都调用一次函数执行:
当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,之后的值不会再调用执行函数。
如果没有符合条件的元素返回 -1

注意: findIndex() 对于空数组,函数是不会执行的。
注意: findIndex() 并没有改变数组的原始值。

代码示例如下:

app.delete('/todos/:id', async (req, res) => {
  try {
    // 获取请求参数
    const queryID = Number.parseInt(req.params.id);
    const db = getDb();
    const index = db.todos.findIndex(todo => todo.id === queryID);
    if (index === -1) 
      return res.status(404).end();
    db.todos.splice(index, 1);

    await saveDb(db)
    res.status(204).end();
  } catch (err) {
    res.status(500).json({
      error: err.message
    })
  }
})

四、express中间件

在中间件中 包含三个参数 req res next
中间件可以执行任何代码
修改req 和 res 响应对象
结束请求响应周期
调用下一个中间件

如果当前的中间件没有结束,要用next()放权,否则程序将一直挂起。

中间件分类

应用程序级别中间件、路由级别中间件、错误处理中间件、内置中间件、第三方中间件

应用程序级别中间件

  1. 不关心请求路径:(在程序执行的时候会被执行到)
app.use(function (req, res, next) {
    console.log('req type', req.method);
    next();
})
  1. 限定请求路径(请求的路径要按照路由指定才能被访问)
//限定请求路径http://localhost:3001/user/1
app.use('/user/:id', function (req, res, next) {
    console.log('user/req type', req.method);
    next();
})

错误处理中间件

在所有的中间件之后 挂载错误处理中间件

next()中被传入除route外的任何内容,express将认为当前是错误请求,并将跳过所有剩余的无错误处理的路由和中间件函数。
router.get('/', async (req, res) => {
  try {
    const todo = await getDb()
    res.status(200).json(todo.todos)
  } catch (err) {
    next(err)
  }
}
//错误处理代码
// 错误处理中间件 --四个参数 缺一不可
app.use((err, req, res, next) => {
  console.log('err', err);
  res.status(500).json({
    error: err.message
  })
})

错误输出
catch结果

内置中间件

express.json() 解析Content-Type为application/json格式的请求体
express.urlencoded() 解析Content-Type为application/x-www-form-urlencoded格式的请求体
express.raw() 解析Conten-Type为 application/octest-stream格式的请求体
express.text() 解析Content-Type为text/plain 格式的请求体
express.static() 托管静态资源文件

第三方中间件

express中间件官网

express路由

express路由中的路径有多种形式可以被匹配访问。

  1. 字符串匹配
    当访问pp.text的时候被匹配
app.post('/pp.text', (req, res) => {
    res.send('string type')
})
  1. 字符串模式匹配
    ?表示可选 ab?cd 可以访问 abcd 也可以访问acd
    *是任意字符
app.post('/ab?cd', (req, res) => {
    res.send('abcd | acd');
})

app.post('/ab*cd', (req, res) => {
    res.send('ab*cd');
})
app.post('/ab(cd)?ef', (req, res) => {
    res.send('ab(cd)?ef')
})
  1. 正则表达式模式匹配
app.post(/b/, (req, res) => {
    res.send('正则表达式')
})

路由参数

当想在路由中传递多个参数的时候,可以使用连字符- 或点 .
在这里插入图片描述
也可以在路由上进行参数校验

//路由校验 转义字符需要\\ http://localhost:3000/student/36
app.get('/student/:num(\\d+)', (req, res) => {
    res.send('/student/:num(\\d+)')
})

总结

命令行语句
递归复制文件01 到 02

cp -r 01 02

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  • 20
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值