Express 基础

Express 是什么

官网地址:http://expressjs.com/

Express 是一个快速,简单,极简的 Node.js web 应用开发框架。通过它,可以轻松的构建各种 web 应用。例如

  • 接口服务
  • 传统的 web 网站
  • 开发工具集成等

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:高度可扩展的开源 Node.js 框架,用于快速创建动态的端到端 REST API。
  • Sails:用于Node.js的 MVC 框架,用于构建实用的,可用于生产的应用程序。
  • NestJs:一个渐进式的 Node.js 框架,用于在 TypeScript 和
    JavaScript(ES6,ES7,ES8)之上构建高效,可扩展的企业级服务器端应用程序。

Express 的开发作者是知名的开源项目创建者和协作者 TJ Holowaychuk。

  • GitHub:https://github.com/tj
  • Express、commander、ejs、co、Koa…

Express 特性

  • 简单易学

  • 丰富的基础 API 支持,以及常见的 HTTP 辅助程序,例如重定向、缓存等

  • 强大的路由功能

  • 灵活的中间件

  • 高性能

  • 非常稳定(它的源代码几乎百分百的测试覆盖率)

  • 视图系统支持 14 个以上的主流模板引擎

Express 应用场景

  • 传统的 Web 网站
  • Ghost
  • 接口服务
  • 服务端渲染中间层
  • 开发工具
  • JSON Server
  • webpack-dev-server

Express 起步

Hello World

使用 Express 创建一个 web 服务,输出 Hello World 响应内容

步骤

mkdir myapp

cd myapp

npm init

npm install express

touch app.js

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

路由基础

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

路由定义采用以下结构:

app.METHOD(PATH, HANDLER)

  • app 是 Express 实例
  • METHOD 是小写的 HTTP
  • 请求方法 PATH 是服务器上的路径 HANDLER
  • 是当路由匹配时执行的功能

示例。
在根路径响应 Hello World!:

app.get('/', function (req, res) {
  res.send('Hello World!')
})

在根路由响应 POST 请求:

app.post('/', function (req, res) {
  res.send('Got a POST request')
})

响应对 /user 路径的 PUT 请求:

app.put('/user', function (req, res) {
  res.send('Got a PUT request at /user')
})

响应对 /user 路由的 DELETE 请求:

app.delete('/user', function (req, res) {
  res.send('Got a DELETE request at /user')
})

请求和响应

Express 应用使用路由回调函数的参数:request 和 response 对象来处理请求和响应的数据。
app.get('/', function (req, res) {
   // --
})

Express 不对 Node.js 已有的特性进行二次抽象,只是在它之上扩展了 web 应用所需的基本功能。

  • 内部使用的还是 http 模块
  • 请求对象继承自 http.IncomingMessage
  • 响应对象继承自:http.ServerResponse

请求对象

req 对象代表 HTTP 请求,并具有请求查询字符串,参数,正文,HTTP 标头等的属性。在本文档中,按照约定,该对象始终称为
req(HTTP 响应为 res),但其实际名称由您正在使用的回调函数的参数确定。

属性:
req.app



req.baseUrl



req.body



req.cookies



req.fresh



req.hostname



req.ip



req.ips



req.method



req.originalUrl



req.params



req.path



req.protocol



req.query



req.route



req.secure



req.signedCookies



req.stale



req.subdomains
req.xhr

方法

req.accepts()



req.acceptsCharsets()



req.acceptsEncodings()



req.acceptsLanguages()



req.get()



req.is()



req.param()



req.range()

响应对象

res 对象表示 Express 应用在收到 HTTP 请求时发送的 HTTP 响应。 在本文档中,按照约定,该对象始终称为 res(并且
HTTP 请求为 req),但其实际名称由您正在使用的回调函数的参数确定。

属性:

• res.app
• res.headersSent
• res.locals
方法:
• res.append()
• res.attachment()
• res.cookie()
• res.clearCookie()
• res.download()
• res.end()
• res.format()
• res.get()
• res.json()
• res.jsonp()
• res.links()
• res.location()
• res.redirect()
• res.render()
• res.send()
• res.sendFile()
• res.sendStatus()
• res.set()
• res.status()
• res.type()
• res.vary()

案例

通过该案例创建一个简单的 CRUD 接口服务,从而掌握 Express 的基本用法。
需求:实现对任务清单的 CRUD 接口服务。

• 查询任务列表
• GET /todos
• 根据 ID 查询单个任务
• GET /todos/:id
• 添加任务
• POST /todos
• 修改任务
• PATCH /todos
• 删除任务
• DELETE /todos/:id

准备数据文件 db.json

{
  "todos": [
    {
      "title": "吃饭",
      "id": 1
    },
    {
      "title": "睡觉",
      "id": 3
    }
  ],
  "users": []
}

封装数据操作模块 db.js

const fs = require('fs')
const { promisify } = require('util')
const path = require('path')

const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)

const dbPath = path.join(__dirname, './db.json')

exports.getDb = async () => {
  const data = await readFile(dbPath, 'utf8')
  return JSON.parse(data)
}

exports.saveDb = async db => {
  const data = JSON.stringify(db, null, '  ')
  await writeFile(dbPath, data)
}

Read 查询列表

app.get('/todos', async (req, res) => {
  try {
    const db = await getDb()
    res.status(200).json(db.todos)
  } catch (err) {
    res.status(500).json({
      error: err.message
    })
  }
})

Read 根据 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
    })
  }
})

Create 添加

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. 数据验证通过,把数据存储到 db 中
    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)
    // 4. 发送响应
    res.status(201).json(todo)
  } catch (err) {
    res.status(500).json({
      error: err.message
    })
  }
})

Update 更新

app.patch('/todos/:id', async (req, res) => {
  try {
    // 1. 获取表单数据
    const todo = req.body
    
    // 2. 查找到要修改的任务项
    const db = await getDb()
    const ret = db.todos.find(todo => todo.id === Number.parseInt(req.params.id))

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

    Object.assign(ret, todo)

    await saveDb(db)

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

Destroy 删除

app.delete('/todos/:id', async (req, res) => {
  try {
    const todoId = Number.parseInt(req.params.id)
    const db = await getDb()
    const index = db.todos.findIndex(todo => todo.id === todoId)
    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
    })
  }
})

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值