使用 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. RocketMQ消息过滤机制源码详解

    #RocketMQ提供了2种消息过滤的方式: TAG 过滤 SQL92 过滤 SQL过滤默认是没有打开的,如果想要支持,必须在broker的配置文件中设置:enablePropertyFilter = ...

  2. Sublime快速在当前目录下新建文件(advanceNewfile插件)

    1.ctrl+shift+p,输入pci,选择第一个,回车 2.输入 advanceNewfile 安装 3.ctrl+alt+n 新建文件自动保存在当前目录下

  3. Rainbond 5.5 发布,支持Istio和扩展第三方Service Mesh框架

    Rainbond 5.5 版本主要优化扩展性.服务治理模式可以扩展第三方 ServiceMesh 架构,兼容kubernetes 管理命令和第三方管理平台. 主要功能点解读: 1. 支持 Istio, ...

  4. java中SimpleDateFormat解析日期格式的问题

    在日常写代码的过程中,我们经常要处理各种格式的日期,常见的日期格式有:"20240601","2024-06-01","2024-6-1". ...

  5. 开源一站式敏捷测试管理平台 itest(爱测试) 6.6.1 发布,安全升级及新增强

    (一)itest 简介及更新说明 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试5合1,又有丰富的统计分析.可按测试包分配测试用例执行 ...

  6. 电脑网卡把报文的vlan tag去掉

    1 现象 现象说明:从电脑的网卡(用的Realtek)进来一个带vlan tag的报文,但是使用wireshark抓取的报文没有vlan tag. 解决方式如下:需要注册表. 参考链接1:https: ...

  7. 【Socket】解决UDP丢包问题

    一.介绍 UDP是一种不可靠的.无连接的.基于数据报的传输层协议.相比于TCP就比较简单,像写信一样,直接打包丢过去,就不用管了,而不用TCP这样的反复确认.所以UDP的优势就是速度快,开销小.但是随 ...

  8. jenkins发布服务失败查看catalina.out启动日志和xxl-job jobhandler naming conflicts

    jenkins发布服务失败查看catalina.out启动日志和xxl-job jobhandler naming conflicts 1.查看tomcat/logs/catalina.out 日志, ...

  9. mysql加解密,substring substring_index函数

    mysql加解密,substring substring_index函数 SELECT to_base64(AES_ENCRYPT('测试串','key12345678')) ;SELECT AES_ ...

  10. linux elasticsearch-8.2.0安装

    1.下载,解压缩,命令行前不要留空格 官网下载地址: https://www.elastic.co/cn/downloads/elasticsearch https://artifacts.elast ...