使用 Node.js 和 Express 构建 Web API

Web API

使用 Web 作为运行应用程序的平台:任何人都可以使用遵守 HTTP浏览器、客户端、软件访问你的应用程序

  • Node.js 有一个名为 HTTP 的核心模块,可帮助构造 Web 应用程序
  • HTTP 模块的速度不及使用框架那么快,Node.js 有许多 Web 框架,例如 Hapi、Fastify、Koa、Express

对 Web 中数据的基本概念

  • 数据存储:一般在文件系统数据库
  • 数据访问:使用 HTTP 的 Web 应用和 API 来提供该数据

在生成 Web 应用程序和 API 时需要考虑:

  • 路由:应用程序根据 URL 地址的不同部分划分为不同的部分,例如 https://baike.baidu.com/item/ 中路径部分 /item
  • 支持不同内容类型:要提供的数据可能以不同的格式存在
  • 身份验证/授权:某些数据可能是敏感数据
  • 读取/写入数据:用户通常需要同时查看和向系统添加数据
  • 成本:若要高效地创建 Web 应用程序和 API,请选择为常见问题提供解决方案的工具和库

Node.js 中的 http 模块

  • 帮助管理请求的对象

    • http.Server: 表示 HTTP Server 的实例,需要指示此对象侦听特定端口地址上的不同事件
    • http.IncomingMessage: 此对象是由 http.Server 或 http.ClientRequest 创建的可读流,使用它访问状态、标头和数据
    • http.ServerResponse: 此对象是 HTTP 服务器在内部创建的流,此类定义响应应有的外观
  • 示例

    const http = require('http');
    const PORT = 3000; // createServer() 方法创建 http.Server 类的实例,其中箭头函数是 createServer() 需要实现的回调函数
    // 1. 箭头函数参数列表:req,res 分别表示请求和响应
    // 2. 箭头函数的函数体:需要对请求和响应进行处理,处理根据项目需求而定
    // 3. 不了解请求或响应,建议温习或学习计算机网络相关知识,也可单独学习 HTTP 协议的相关内容
    const server = http.createServer((req, res) => {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('hello world');
    }); // 开始侦听请求,此时服务器即可接受客户端请求
    server.listen(PORT, () => {
    console.log(`listening on port ${PORT}`)
    })
  • Node.js 流

    流 (stream) 不是 Node.js 概念,而是操作系统概念,它定义数据来回传输的方式

    流是 Node.js 中的基本数据结构

    • 可以读取和写入数据
    • 可以发送和接收消息或事件

    之前的 reqres 参数都是流

    • 使用 on() 方法侦听来自客户端请求的传入数据
    • 使用 end() 方法发送回客户端的数据

创建 Express 框架 Web 应用程序

Express 框架

为什么要将 Express 作为构建下一个应用的框架?

  • 过多便捷高效的功能
  • 使复杂性抽象化,使整个开发体验变得更加容易
  • 解决常见的 Web 问题,有助于解决路由管理、缓存、重定向等
  • 由数百万开发者信任,意味着维护性和保障

Express 中的路由管理

  • Express 框架使用 URL、路由、HTTP 谓词进行路由管理

  • Express 可帮助注册路由,并将它们与适当的 HTTP 谓词配对以组织 Web 应用程序

  • 示例

    // 该请求具有与 HTTP 谓词 get 关联的地址 /products
    app.get('/products', (req, res) => {
    // handle the request
    }) // 看待 get 对 /products 和 post 对 /products 不同
    app.post('/products', (req, res) => {
    // handle the request
    })

Express 支持许多不同的内容格式,这些可以返回给调用客户端

  • 若要返回纯文本,可使用 send() 方法

  • 对于 JSON 等其他类型的数据,可通过 json() 方法确保内容类型和数据转换正确

  • 示例

    // Express 框架
    res.send('plain text')
    res.json({ id: 1, name: "Catcher in the Rye" }) // 原生
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({ id: 1, name: "Catcher in the Rye" }));

若要开始使用 Express 框架开发 Node.js 应用程序,建议首先初始化 Node.js 项目以便下载的任何依赖项最后都在 package.json 文件中(这是针对为 Node.js 运行时开发的应用的一般建议),Express 框架创建 Web 应用程序的基本步骤:

  • 实例化应用
  • 定义路由和路由处理程序
  • 配置中间件
  • 启动应用

Express 示例

一个基本的 Express Web 程序

  • 初始化项目:在命令行随便创建一个目录 express-web,进入目录执行 npm init -y && npm install express,其中 && 表示前一个命令顺利执行后一个才能执行

  • 在 package.json 文件中确认 express 安装

    "dependencies": {
    "express": "^4.18.2"
    }
  • 创建服务端,先创建名为 app.js 的文件

    /**
    * app.js
    */
    const express = require('express'); const port = 3000;
    // 通过调用 express() 方法创建 Express 应用程序的实例
    const app = express(); // 设置 Web 应用的根路由 '/',访问根路由会响应文本 'Hello World!'
    app.get('/', (req, res) => res.send('Hello World!')); // 通过调用 listen() 方法启动 Web 应用
    app.listen(port, () => console.log(`Example app listening on port ${port}!`));
  • 在终端中,运行 node app.js 命令以启动 Express Web 应用

    • 应会看到以下输出 Example app listening on port 3000!,此时程序是处于监听状态
    • 在浏览器中访问 http://localhost:3000,会看到以下输出 Hello World!
  • 在终端中,按 Ctrl+C 即可停止 Express Web 程序

Web 应用返回 JSON 数据

  • 打开 app.js 文件,在原有的基础上添加以下代码

    app.get("/products", (req,res) => {
    const products = [
    {
    id: 1,
    name: "hammer",
    },
    {
    id: 2,
    name: "screwdriver",
    },
    {
    id: 3,
    name: "wrench",
    },
    ]; res.json(products);
    });
  • 再次运行 app.js,浏览器访问 http://localhost:3000/products,可以看到

    [{"id":1,"name":"hammer"},{"id":2,"name":"screwdriver"},{"id":3,"name":"wrench"}]

使用中间件管理请求生命周期

当请求到达 Web 应用程序时,你可能需要验证用户是否已登录或是否允许他们查看特定资源

考虑将请求作为一系列步骤来处理

  • pre 请求:调查用户是否通过请求标头发送了正确的凭据
  • 构造响应:与某种数据源(如数据库或终结点)通信
  • post 请求: 一个可选步骤,用于在请求处理后运行一段代码

Express 框架对以此方式处理请求提供内置支持

  • Express 中的 pre 或 post 请求称为“中间件”

  • 若要运行 pre 或 post 请求,需要对 Express 实例化对象实现 use() 方法

  • 示例

    app.use((req, res, next) => {});
    • req: 包含请求标头和调用 URL 的传入请求
    • res: 用于写入要发送回调用客户端的标头和数据等信息的响应流
    • next: 指示请求正常并已准备好处理的参数,如果未调用 next() 则请求的处理将停止

如果你的路由从中间件运行 pre 或 post 请求中生效,请设置它:

  • 需要在请求之前运行的中间件(pre 请求)定义在实际请求前
  • 需要在请求之后运行的中间件(post 请求)定义在实际请求后
// 有效设置
app.use((req, res, next) => {
// Pre request,进行验证
})
app.get('/protected-resource', () => {
// Handle the actual request,Pre 中验证通过方可执行
})
app.use((req, res, next) => {
// Post request,可选
}) // 没有使用
app.get('/login', () => {}) // 将 pre 请求中间件代码作为处理请求的参数来运行
app.get(
'/route',
() => {
// Pre request middleware
},
() => {
// Handle the actual request
}
);

实际中使用的身份验证/授权功能需要比我们的示例更可靠一些,有必要了解 OAuth、JSON Web 令牌、JWT 等概念和库 bcrypt,以确保为应用提供适当的保护级别

在 Node.js 中使用 JavaScript 路由管理

URL 是用户在浏览器等客户端中输入的用于查找特定服务器和特定资源的地址

scheme:[//authority]path[?query][#fragment]
  • Scheme: 协议
  • authority: 颁发机构,域名、主机、IP
  • path: 路径部分包含零至多个段,是服务器中以站点为根路径
  • query: 可以通过请求特定页面中的多条记录来进一步筛选数据
  • fragment: 请求内容更加具体

路由是 URL 的一个分段,通常指向特定资源

  • Express 定义路由,并将不同处理程序与它们关联

    // 路由参数写入请求对象 req 上的 params 属性中
    app.get('/products/:id', (req, res) => {
    // 如果请求 /products/144,那么 req.params.id=144
    })
  • Express 具有一种处理查询参数的简单方法

// 查询参数会写入到 res 请求对象上的 query 查询对象
app.get('/products', (req, res) => {
// 如果请求 /products?page=1&pageSize=20,那么 res.query 等价 {page: 1, pageSize: 20}
})

实现对读取和写入数据的支持

在 products 资源上实现简单的 CRUD API

const express = require('express')
const app = express()
const port = 3000 // 导入正文分析器,需要将传入数据转换为可读的格式
let bodyParser = require('body-parser');
// 将传入的正文数据分析为预期格式
app.use(bodyParser.json()); // 存储数据,但一般此处是由数据库
let products = []; // C 创建
app.post('/products', function (req, res) {
const newProduct = { ...req.body, id: products.length + 1 }
products = [ ...products, newProduct]
res.json(newProduct);
}); // R 读取
app.get('/products', (req, res) => {
res.json(products);
}) // U 更新
app.put('/products', function (req, res) {
let updatedProduct;
products = products.map(p => {
if (p.id === req.body.id) {
updatedProduct = { ...p, ...req.body };
return updatedProduct;
}
return p;
})
res.json(updatedProduct);
}); // D 删除
app.delete('/products/:id', function (req, res) {
const deletedProduct = products.find(p => p.id === +req.params.id);
products = products.filter(p => p.id !== +req.params.id);
res.json(deletedProduct);
}); // 启动,进行监听
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

Express 有一种 route() 方法,可以对代码进行分组使其更易于阅读

const express = require('express')

const app = express()
const port = 3000 let bodyParser = require('body-parser');
app.use(bodyParser.json()); let products = []; // 下面不同处
app.route('/products')
.get((req, res) => {
res.json(products);
})
.post((req, res) => {
const newProduct = { ...req.body, id: products.length + 1 }
products = [...products, newProduct]
res.json(newProduct);
})
.put((req, res) => {
let updatedProduct;
products = products.map(p => {
if (p.id === req.body.id) {
updatedProduct = { ...p, ...req.body };
return updatedProduct;
}
return p;
})
res.json(updatedProduct);
})
.delete((req, res) => {
const deletedProduct = products.find(p => p.id === +req.body.id);
products = products.filter(p => p.id !== +req.body.id);
res.json(deletedProduct);
}); app.listen(port, () => console.log(`Example app listening on port ${port}!`))

使用 Node.js 和 Express 构建基本的 Web API的更多相关文章

  1. 一个迷你的 Node.js 基于 Express 的 MVR 模式的 API工程 的分析

    1. 工程说明 该工程是基于 Express 库,编写的一个 API 查询返回的一个微型应用. API Resource 就是把 API 的内容当做网络资源去处理.工程中的路由访问也是返回 API 内 ...

  2. 如何设计一个基于Node.js和Express的网站架构?

    前言 今年七月份,我和几个小伙伴们合伙建立了一个开发团队.业务开展如火如荼的同时,团队宣传就提上了日程,所以迫切需要搭建公司网站出来.确定目标后我们就开始考虑如果构建一个企业网站.先是进行业内调查,看 ...

  3. Node.js基于Express框架搭建一个简单的注册登录Web功能

    这个小应用使用到了node.js  bootstrap  express  以及数据库的操作 :使用mongoose对象模型来操作 mongodb 如果没了解过的可以先去基本了解一下相关概念~ 首先注 ...

  4. Node.js系列-express(上)

    前言 Node.js系列的第一篇:http,大概描述了通过使用node.js内置的api创建一个服务并监听request实现简单的增删改查.现在,我们就通过通读express官网及使用express框 ...

  5. Code Your First API With Node.js and Express: Set Up the Server

    How to Set Up an Express API Server in Node.js In the previous tutorial, we learned what the REST ar ...

  6. Node.js、express、mongodb 实现分页查询、条件搜索

    前言 在上一篇Node.js.express.mongodb 入门(基于easyui datagrid增删改查) 的基础上实现了分页查询.带条件搜索. 实现效果 1.列表第一页. 2.列表第二页 3. ...

  7. Node.js、express、mongodb 入门(基于easyui datagrid增删改查)

    前言 从在本机(win8.1)环境安装相关环境到做完这个demo大概不到两周时间,刚开始只是在本机安装环境并没有敲个Demo,从周末开始断断续续的想写一个,按照惯性思维就写一个增删改查吧,一方面是体验 ...

  8. node.js和express.js安装和使用步骤 [windows]

    PS: NODEJS:https://nodejs.org NPM:https://www.npmjs.com/ 一.node.js安装与配置 到https://nodejs.org/en/downl ...

  9. Feathers JS – 基于 Express 构建数据驱动的服务

    Feathers 是一个轻量的 Web 应用程序框架,基于 NodeJS 最流行​​的 Web 框架——Express.这使得它很容易使用 socket.io 来创建 RESTful Web 服务和实 ...

  10. node.js框架express的安装

    node.js框架express的安装 首先假定你已经安装了 Node.js,接下来为你的应用创建一个目录,然后进入此目录并将其作为当前工作目录. $ mkdir myapp $ cd myapp 通 ...

随机推荐

  1. elementui table tree懒加载只能执行一次的解决办法

    绑定 table的:key为随机值,在每次查询更新table时,更改key,就能刷新 table tree 懒加载只能第一次有效的问题, 本来那个懒加载只能执行一次,即使重新绑定了数据列表,再展开,也 ...

  2. docker部署php8.0 nginx1.18 mysql5.7 dnmp环境

    php8.0 nginx1.18 mysql5.7 #安装docker wget -O /etc/yum.repos.d/ali_docker-ce.repo https://mirrors.aliy ...

  3. svg动画导致持续占用CPU

    1.在一次性能优化中突然发现一个svg矢量图动画导致CPU持续占用的问题,该svg在web中使用, 即使webview释放之后,CPU依然占用达到10%,6s+上测试结果 svg如下所示: <s ...

  4. 微信小程序跳转重新加载目标页

    可用于在首次进入到小程序后就执行性了首页的onLoad方法,等你再去点击其它页面再回来的时候就不会加载onLoad了,比如你跳到登录页后再返回到首页会发现首页啥数据都没加载,所以你在登录那边进行跳转的 ...

  5. uniapp+django登录页面实现

    前后端联动 概述 以一个简单的登录功能为例说明,uni-app的前后端交互 项目地址: 效果图 前端页面开发 项目地址: 后端页面开发 项目地址: 其他参考资料 1.Django项目和uni-app项 ...

  6. BigDecimal的小数位

    在使用BigDecimal的divide方法进行除法运算时,需要传入两个参数:被除数和除数.如果要对除法结果进行保留小数位数的处理,可以使用该方法的重载形式,传入一个指定小数位数和舍入规则的MathC ...

  7. 获取前(后)x月的日期

    package com.jesims.busresume.web; import org.springframework.stereotype.Service; import java.text.Da ...

  8. json LocalDateTime转对象

    json LocalDateTime转对象 feign.codec.DecodeException: JSON parse error: Can not deserialize instance of ...

  9. NumPy 差分、最小公倍数、最大公约数、三角函数详解

    NumPy 差分 离散差分意味着相邻元素之间的减法. 例如,对于 [1, 2, 3, 4],离散差分将是 [2-1, 3-2, 4-3] = [1, 1, 1] 要找到离散差分,使用 diff() 函 ...

  10. RSA密码系统的特定密钥泄露攻击与Coppersmith方法的应用

    PrimiHub一款由密码学专家团队打造的开源隐私计算平台,专注于分享数据安全.密码学.联邦学习.同态加密等隐私计算领域的技术和内容. RSA密码系统作为当前最广泛使用的公钥加密算法之一,其安全性依赖 ...