Express基础

1 简介

Express是一个基于Node平台的web应用开发框架,它提供了一系列的强大特性用来创建各种Web应用。

  • 提供了方便简洁的路由定义方式;
  • 对获取HTTP请求参数进行了简化处理;
  • 对模板引擎支持程度高,方便渲染动态HTML页面;
  • 提供了中间件机制有效控制HTTP请求;
  • 拥有大量第三方中间件对功能进行扩展。

可以使用 npm install express 命令安装Express,安装后包含两个文件夹:

  • node_modules:包含所有依赖包;
  • package-lock.json:所有依赖包的清单。

再在根目录新建文件server.js,具体使用方法见第3节。

2 原生Node.js与Express框架路由实现对比

2.1 原生Node.js路由

app.on('request', (req, res) => {
  // 获取客户端的请求路径
  let {pathname} = url.parse(req.url)
  // 对请求路径进行判断,不同的路径地址响应不同的内容
  if (pathname == '/' || pathname == 'index') {
    res.end('欢迎来到首页!')
  } else if (pathname == '/other') {
    res.end('欢迎来到其他页面!')
  } else if (pathname == '/about') {
    res.end('欢迎来到关于页面!') 
  } else {
    res.end('抱歉,没有找到相关页面!')
  }
})

2.2 Express路由

// 当客户端以get方式访问/时
app.get('/', (req, res) => {
  // 对客户端做出响应
  res.send('使用get方式请求了/路由')
})

// 当客户端以post方式访问/about路由时
app.post('/about', (req, res) => {
  res.send('使用post方式请求了/about路由')
})

3 Express框架简单使用

启动一个Express网站服务器并开启一个“/”的路由监听:

// 1.引入Express框架,并创建Express实例
const express = require('express')
// 2.创建网站服务器对象
const app = express()

// 3.定义路由
// 第一个参数是请求的路径,'/'代表根路径localhost:3000
// 第二个参数是一个函数,req是request的缩写,表示客户端提交过来的数据
// res是respond的缩写,表示要响应回的数据
app.get('/', (req, res) => {
  // send()方法,响应给客户端信息
  // 1. send方法内部会检测响应内容的类型
  // 2. send方法会自动设置http状态码
  // 3. send方法会帮我们自动设置响应的内容类型及编码
  res.send('Hello Express!')
})

// 4.监听端口,第二个参数回调函数启动成功后执行的内容
app.listen(3000, () => {
  console.log('网站服务器启动成功!')
})

输入node server.js启动服务器,但因node项目在每次编辑后都要重新启动才会生效,所以使用nodemon工具来自动启动服务,推荐全局安装,命令如下:

npm install -g nodemon

安装成功后就可以使用命令nodemon server.js来启动服务。

4 中间件

中间件就是一系列方法,可以接收客户端发来的请求、可以对请求做出响应,也可以将请求继续交给下一个中间件继续处理。
image.png
中间件主要由两部分构成,中间件方法以及请求处理函数。
中间件方法由Express提供,负责拦截请求,请求处理函数由开发人员提供,负责处理请求。
可以针对同一个请求设置多个中间件,对同一个请求进行多次处理。

app.get('/request', (req, res, next) => {
  req.name = 'Jack'
  next()
})
app.get('/request', (req, res) => {
  res.send(req.name)
})

默认情况下,请求从上到下依次匹配中间件,一旦匹配成功,终止匹配。可以调用 next() 方法将请求的控制权交给下一个中间件,直到遇到结束请求的中间件。

4.1 万能中间件 app.use

app.use 匹配所有的请求方式,可以直接传入请求处理函数,代表接收所有的请求。

app.use((req, res, next) => {
  console.log(req.url)
  next()
})

app.use 第一个参数也可以传入请求地址,代表不论什么请求方式,只要是这个请求地址就接收这个请求。

app.use('/about', (req, res, next) => {
  console.log(req.url)
  next()
})

4.2 中间件的应用

  1. 路由保护,客户端在访问需要登录的页面时,可以先使用中间件判断用户登录状态,用户如果未登录,则拦截请求,直接响应,禁止用户进入需要登录的页面。
// 登录过程模拟
app.get('/admin', (req, res, next) => {
  // 用户没有登录
  let isLogin = false
  if (isLogin) {
    // 如果用户登录,让请求继续向下执行
    next()
  } else {
    res.send('您还没有登录,不能访问当前页面!')
  }
})

app.use('/admin', (req, res, next) => {
  res.send('您已经登录,可以访问当前页面!')
})
  1. 网站维护公告,在所有路由的最上面定义接收所有请求的中间件,直接为客户端做出响应,网站正在维护中。
app.use((req, res, next) => {
  res.send('当前网站正在维护。。。')
  // 由于没有使用next()传递给下一个中间件,所以会停留在此处
})
  1. 自定义404页面,把中间件定义在最后面。
app.use((req, res, next) => {
  // 为客户端响应404状态码以及提示信息
  res.status(404).send('当前访问的页面是不存在的。')
})

4.3 处理错误中间件

在程序执行的过程中,不可避免的会出现一些无法预料的错误,比如文件读取失败,数据库连接失败。错误处理中间件是一个集中处理错误的地方。

app.get('/index', (req, res) => {
  // 创建一个错误实例并抛出
  throw new Error('程序发生了未知错误!')
})

app.use((err, req, res, next) => {
  // 为客户端响应500状态码以及提示信息
  res.status(500).send(err.message)
})

throw new Error('程序发生了未知错误!') 实际上是一个同步代码,如果异步代码在执行过程中出现了错误,这样是无法捕捉到的。这个时候需要手动的触发错误处理中间件,当异步API出错时,需要调用 next() 方法,并把错误传入 next() 方法。

app.get('/', (req, res, next) => {
  fs.readFile('/file-does-not-exist', (err, result) => {
    if (err != null) {
      next(err)
    } else {
      res.send(result)
    }
  })
})

4.4 捕获错误

在nodejs中,异步API的错误信息都是通过回调函数获取的,支持Promise对象的异步API发生错误可以通过catch方法捕获。异步函数执行如果发生错误要如何捕获错误呢?

try catch 可以捕获异步函数以及其他同步代码在执行过程中发生的错误,但是不能其他类型的API发生的错误。下面代码中把读取文件改造成支持异步函数的形式。

const promisify = require('util').promisify
const readFile = promisify(fs.readFile)

app.get('/', async (req, res, next) => {
  try {
    await readFile('/aaa.js')
  } catch(err) {
    next(err)
  }
})

4.5 构建模块化路由

// 创建路由对象
const home = express.Router()
// 将路由和请求路径进行匹配
app.use('/home', home)
// 在home路由下继续创建二级路由
home.get('/index', () => {
  // 访问路径/home/index
  res.send('欢迎来到主页!')
})

image.png

5 GET参数的获取

Express框架中使用req.query即可获取GET参数,框架内部会将GET参数转换为对象并返回。

// 接收地址栏中问号后面的参数
// 例如:http://localhost:3000/?name=zhangsan&age=30
app.get('/', (req, res) => {
  console.log(req.query) 
  // {"name": "zhangsan", "age": "30"}
})

6 POST参数的获取

Express中接收post请求参数需要借助第三方包 body-parser。它其实是Express官方提供的,官方为了让包体积更加小巧,将一些工具剥离出来,供开发者按需安装。
安装命令: npm install body-parser 。

// 引入body-parser模块
const bodyParser = require('body-parser')
// 配置body-parser模块,拦截所有请求
// extended: false 方法内部使用querystring模块处理请求参数的格式
// extended: true 方法内部使用第三方模块qs处理请求参数的格式
app.use(bodyParser.urlencoded({extended: false}))
// 接收请求
app.post('/add', (req, res) => {
  // 接收请求参数
  console.log(req.body)
})

注:可以直接使用app.use(express.json());代替body-parser。
【1】https://stackoverflow.com/questions/61551926/express-json-vs-body-parser
【2】https://cloud.tencent.com/developer/ask/37434

7 Express路由参数

在定义时,可以显式定义请求接收的参数,在url后面用冒号加上参数:

// localhost:3000/find/123
app.get('/find/:id', (req, res) => {
  console.log(req.params) // {id: 123}
})

如果要传递多个参数,可以继续添加斜杠和冒号。

8 静态资源的处理

通过Express内置的express.static可以方便地托管静态文件,例如img、CSS、JavaScript 文件等。

const path = require('path')
app.use(express.static(path.join(__dirname, 'public')))

现在,public目录下面的文件就可以访问了。

除此之外,还可以控制路径,可以在添加一个参数static

app.use('static', express.static(path.join(__dirname, 'public')))

再访问静态资源的时候就要在url中加入static,如:http://localhost:3000/static/hello.html

9 跨域处理

跨域:https://juejin.cn/post/6844904126246027278#heading-1
现在如有接口:

app.get('/user', (req, res) => {
  res.send({
    name: 'syz',
    age: '18',
  })
})

该接口的访问地址是:http://localhost:3000/user。使用静态资源处理,在public文件夹中新建index.html
image.png
此时通过http://localhost:3000/index.html可以访问,在body中添加如下内容:

<script>
  fetch('http://localhost:3000/user').then(res => res.json).then(data => {
    console.log(data)
  })
</script>

再次访问http://localhost:3000/index.html,就可以在Console中看到输出的对象:{name: "syz", age: "18"}
这是数据是可以正常访问到的,此时右键index.html,利用vscode插件Live server打卡,该插件会启动一个以5500为端口的服务:
image.png
访问地址为:http://127.0.0.1:5500/public/index.html,此时可以发现Console无法请求到数据了,并报了跨域错误。
image.png
处理跨域问题需要用到第三方库:npm i cors,在server.js中添加如下代码:

// 引入cors,返回的是一个函数,直接()执行,执行后是一个Express中间件,app.use使用它即可
app.use(require('cors')())

再访问http://127.0.0.1:5500/public/index.html即可获取到数据。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值