Express 基础与简单应用(搭建服务器、处理不同HTTP请求方法)

51 阅读4分钟

1 什么是Express

Express 是一个基于 Node.js 的 Web 应用程序框架。它提供了一组简洁而强大的工具和功能,用于开发 Web 和 API 服务器端应用程序。

Express提供了一系列中间件(middlewares)和路由(routing)功能,以处理请求、响应和中间处理逻辑,同时提供了模板引擎支持、静态文件服务、错误处理等功能。

Express 的优势在于其简洁性和灵活性,可以根据需要选择和集成其他中间件、插件和功能来满足具体的开发需求。它被广泛用于构建 Web 应用程序、API 服务器、单页应用程序等,是 Node.js 生态系统中最受欢迎和常用的框架之一。

2 安装express

在 Node.js 中可以通过使用 Node 包管理器(npm)来安装express:

  1. 打开terminal,切换到项目目录
  2. npm init初始化项目
  3. npm i express安装express模块,这会从 npm 仓库下载 Express 包及其依赖,并将其安装到你的项目的 node_modules 目录下
  4. 在你的代码文件中引入express模块const express = require('express')

3 express搭建简单web服务器

安装好express框架后,我们可以利用它搭建一个简单的web服务器:

const express = require('express');
const app = express();      //app:express应用程序对象
const port = 3000;

// 处理根路由
app.get('/', (req, res) => {
  res.send('Hello, Express!');
});

// 启动服务器
app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

在第2行中,我们调用express()函数,并将返回值赋给变量app。借助变量app,我们启动服务器、监听端口 3000,并处理根路由 / 的 GET 请求。当客户端发起 GET 请求到根路径时,服务器将发送响应 "Hello, Express!"。

note:express() 函数返回一个对象,该对象具有许多可用于创建服务器的方法和属性,我们将其称为Express 应用程序对象并赋值给变量app

通过使用Express应用程序对象(即app),你可以定义路由、处理请求和响应、设置应用程序的配置等等。它是构建 Express 服务器的核心对象。

Express 应用程序对象具有一些重要的方法和属性,例如:

  • app.listen():用于启动服务器并监听指定的端口
  • app.get()app.post()app.put()app.delete() 等:路由处理函数,根据请求的路径和HTTP方法执行相应操作。
  • app.use():用于添加中间件函数来处理请求。
  • app.set()app.get():用于设置和获取应用程序的设置。
  • app.locals:用于存储应用程序的本地变量。
  • app.router:用于路由处理的中间件。

4 express处理不同http请求方法

4.1 GET

const fs = require('fs');
const express = require('express');
const app = express();

const tours = JSON.parse(
  fs.readFileSync(`${__dirname}/dev-data/data/tours-simple.json`, 'utf-8')
);

app.get('/api/v1/tours', (req, res) => {
  res.status(200).json({
    status: 'success',
    results: tours.length,
    data: {
      tours,
    },
  });
}); 

const port = 3000;
app.listen(port, () => {
  console.log(`App running on port ${port}...`);
});

在上面的代码中,9~17行是处理GET请求的代码,其中我们做了一些事:

  • 使用app.get()函数定义get方法的路由和路由处理函数(route & route handler)。
  • res.status() 函数是 Express 中用于设置响应的 HTTP 状态码的方法。它允许你在发送响应之前设置响应的状态码。
  • res.json() 方法是 Express 中用于发送 JSON 响应的方法。它将一个 JavaScript 对象或数组转换为 JSON 字符串,并将其作为响应的主体发送给客户端。res.json() 方法会自动设置响应的 Content-Type 为 application/json

4.2 POST

...
app.use(express.json()); //middleware
...

app.post('/api/v1/tours', (req, res) => {
  const newId = tours[tours.length - 1].id + 1;
  const newTour = Object.assign({ id: newId }, req.body);
  tours.push(newTour);

  fs.writeFile(
    `${__dirname}/dev-data/data/tours-simple.json`,
    JSON.stringify(tours),
    (err) => {
      res.status(201).json({
        status: 'success',
        data: {
          tour: newTour,
        },
      });
    }
  );
});

在上面的代码中,我们做了一些事:

  • 使用中间件函数app.use(express.json()),用于解析传入请求的JSON数据。当客户端发送带有 JSON 数据的 POST 请求(或 PUT 请求)时,通常需要将请求体中的 JSON 数据解析为 JavaScript 对象,以便在服务器端进行处理。express.json() 中间件就是用来完成这个解析过程的。
  • 我们希望将tours写入tours-simple.json文件,但tours是js对象, 因此在12行,使用JSON.stringfy()函数将js对象转换为json字符串,以写入json文件。

4.3 获取路由参数

路由参数是在URL路径中的一部分,用于标识和区分不同的资源或页面,使用冒号(:)来定义,并在URL中使用对应的值来替代。

示例:/users/:id,其中:id是路由参数,可以匹配任何具体的用户ID值。

express提供了req.params对象用以获取用户请求中的路由参数。

app.get('/api/v1/tours/:id', (req, res) => {
  const id = req.params.id * 1;
  const tour = tours.find((el) => el.id === id);

  if (!tour) {
    return res.status(404).json({
      status: 'fail',
      message: 'Invalid ID',
    });
  }

  res.status(200).json({
    status: 'success',
    data: {
      tour,
    },
  });
});

在上面的代码中:

  • req.params 是 Express 中用于获取路由参数的对象。如果客户端发送的请求路径是/api/v1/tours/5,那么req.params的值将为{id:'5'}
  • 第2行中,将文本值转换为数值

4.4 PATCH

PATCHPUT 是 HTTP 协议中用于更新资源的方法,区别在于:

  • PUT 方法用于替换整个资源,要求提供完整的资源表示。可以创建或完全替换资源。
  • PATCH 方法用于局部更新资源,只需提供要更新的字段或属性。保持其他字段不变。
app.patch('/api/v1/tours/:id', (req, res) => {
  if (req.params.id * 1 > tours.length) {
    return res.status(404).json({
      status: 'fail',
      message: 'Invalid ID',
    });
  }

  res.status(200).json({
    status: 'success',
    data: {
      tour: '<Updated our tour...>',
    },
  });
});

4.5 DELETE

app.delete('/api/v1/tours/:id', (req, res) => {
  if (req.params.id * 1 > tours.length) {
    return res.status(404).json({
      status: 'fail',
      message: 'Invalid ID',
    });
  }
  res.status(204).json({
    status: 'success',
    data: null
  });
});

note:状态码 204 表示 "No Content",它表示服务器成功处理了请求,但没有返回任何内容作为响应。

4.6 路由重构

我们可以将上面所有操作的路由和路由处理函数分开。

const getAllTours = (req, res) => {...};
const getTour = (req, res) => {...};
const createTour = (req, res) => {...};
const updateTour = (req, res) => {...};
const deleteTour = (req, res) => {...};

app
  .route('/api/v1/tours')       //路由对象
  .get(getAllTours)
  .post(createTour);

app
  .route('/api/v1/tours/:id')
  .get(getTour)
  .patch(updateTour)
  .delete(deleteTour);

在上面的代码中,我们做了两件数:

  1. 将路由处理函数定义到处理程序外部。
  2. 使用app.route() 创建链式路由处理程序。 它可以用于在一个地方定义针对同一路径的多个 HTTP 方法的处理逻辑,提高代码的可读性和可维护性。