使用 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. Android 13 - Media框架(26)- OMXNodeInstance(三)

    关注公众号免费阅读全文,进入音视频开发技术分享群! 上一节我们了解了OMXNodeInstance中的端口定义,这一节我们一起来学习ACodec.OMXNode.OMX 组件使用的 buffer 到底 ...

  2. 图像处理技术OpencvSharp入门

    目录 第一部分 初识Opencv 1.C# 下Opencv库 2.安装OpenCvSharp 第二部分 OpencvSharp入门 1.加载图像文件 2.显示图像 第三部分 基础应用 1.颜色转换 2 ...

  3. windows下vscode连接linux(虚拟机)进行(伪)远程开发

    免责声明 本文乃至本系列是对网络上传播的内容进行整理以梳理流程,且因为篇幅限制会精简内容,适合面向具有计算机类基础知识的人群,本文内容较为笼统,只有大体上的逻辑,具体的细节肯定是官网上写的准而全,望读 ...

  4. 前端项目报EISDIR: illegal operation on a directory, read这个错误

    背景: 我用webstorm开发前端页面时,项目用Vue3来开发,出现如下报错. 原因: 这个报错是由于代码中引入的一些组件或者模块路径不正确导致的,在vue2中,引入组件是下面这样写的: impor ...

  5. java检测当前CPU负载状态的方法

    1.java检测当前CPU负载状态 在Java中,直接检测CPU负载状态并不像在操作系统命令行中那样简单,因为Java标准库并没有直接提供这样的功能.但是,我们可以通过几种方法间接地获取CPU负载信息 ...

  6. vmware vmnat1和vmnat8在真机网络适配器中消失

    在真机的网络适配器中,发现只有两张网卡.缺少vmnat1和vmnat8 一,查看虚拟网络编辑器是否连接 二,如果没有连接,勾选连接就好了. 三,如果连接了,真机网络适配器仍然只有两张网络适配器. 1. ...

  7. kettle从入门到精通 第六十四课 ETL之kettle kettle中执行SQL脚本步骤,使用需当心

    1.群里有不定时会有同学反馈执行SQL脚本步骤使用有问题,那么咱们今天一起来学习下该步骤.trans中的执行SQL脚本有两方面功能,使用时需小心,不然很容易踩坑. 官方定义: 翻译: 您可以使用此步骤 ...

  8. C++中 符号的优先级

    符号 运算顺序 :: 从左至右 a++ a-- type() type{} a() a[] . -> 从左至右 ! ~ ++a --a +a -a (type) sizeof &a *a ...

  9. 使用 ClickHouse 做日志分析

    原作:Monika Singh & Pradeep Chhetri 这是我们在 Monitorama 2022 上发表的演讲的改编稿.您可以在此处找到包含演讲者笔记的幻灯片和此处的视频. 当 ...

  10. Vue学习:6.认识计算属性

    计算属性是 Vue.js 提供的一种特殊属性,用于在模板中动态计算和返回数据.计算属性使得在模板中使用动态计算的数据变得非常简洁和方便,同时又能保持响应式更新的特性,提高了代码的可读性和可维护性. 与 ...