博客 | NGINX

使用 NGINX Plus 和 NGINX JavaScript 模块批量处理 API 请求

NGINX-F5-horiz-black-type-RGB 的一部分
里克·尼尔森缩略图
里克·尼尔森
2018 年 5 月 24 日发布

NGINX Plus R15发布的NGINX JavaScript 模块版本现在可以发出子请求,这意味着可以在 JavaScript 代码中发起请求。 这使得一系列全新的用例能够得到解决。

其中一个用例是批处理 API 请求,以便来自客户端的单个 API 请求可以转换为对一组后端服务器的多个 API 请求,并且响应聚合为对客户端的单个响应。 在此博客中,我们使用一个电子商务网站作为示例——当客户端请求有关特定产品的信息时,会向三个后端服务发出子请求:目录、库存和客户评论。

这篇文章基于NGINX Plus R15公告中的子请求示例,该示例展示了如何使用子请求将相同的请求发送到两个后端服务器,并且只向客户端返回第一个响应。

[编辑——这篇文章是探讨 NGINX JavaScript 模块用例的几篇文章之一。 有关完整列表,请参阅NGINX JavaScript 模块的用例

该帖子已更新为使用js_import指令,该指令取代了 NGINX Plus R23 及更高版本中的js_include指令。 有关更多信息,请参阅NGINX JavaScript 模块的参考文档 -示例配置部分展示了 NGINX 配置和 JavaScript 文件的正确语法。 ]

介绍

这篇文章的目的是提供简单直接的 API 请求批处理的工作示例。 这些示例满足以下所有要求:

  • 所有请求均使用 HTTP GET方法。
  • 所有响应均为 JSON 格式。
  • 支持两种风格的 API 请求:

    • API 程序的参数是 URI 的最后一个元素。我们称之为最终元素请求样式。 在我们的示例中,客户端对/batch-api/product/14286的请求会生成对/myapi/catalog/14286/myapi/inventory/14286/myapi/review/14286 的请求。
    • 参数在 URI 的查询字符串中标识。我们称之为查询字符串请求样式。 在示例中,对/batch-api2/product?item=14286 的请求会生成对/myapi/catalog.php?item=14286/myapi/inventory.php?item=14286/myapi/review.php?item=14286的请求。

    请注意,无论哪种样式,查询字符串中都可以有附加参数。

  • 客户端请求触发的子请求集是动态可配置的,这意味着我们无需手动编辑 NGINX Plus 配置并重新加载它即可更改它。
  • 对后端服务器的 API 请求彼此独立。

解决方案概述

除了使用 NGINX JavaScript 的新子请求功能之外,该解决方案还利用了 NGINX Plus 的键值存储功能,允许使用NGINX Plus API动态地更改配置。

下图说明了两种支持的请求样式。

最终元素请求样式:

客户端向 API 发出最终元素样式请求

查询字符串请求样式:

客户端向 API 发出查询字符串样式的请求

在这两个例子中,客户端需要从目录、库存和评论服务中获取有关产品的信息。 它向 NGINX Plus 发送一个请求,将项目编号作为 URI 的一部分传递或在查询字符串中传递。 然后将请求发送到这三个服务,并将响应聚合为对客户端的单个响应。

要使 NGINX Plus 正常工作,需要两个组件: JavaScript 程序NGINX Plus 配置

JavaScript 程序

每个客户端请求都会调用 JavaScript 函数batchAPI() 。 它从键值存储中获取以逗号分隔的 API URI 列表并对其进行迭代,为每个 URI 发出一个子请求,并指定回调函数done()来处理每个响应。 对于最终元素样式的请求,URI 的最后一个元素(存储在 NGINX 变量$uri_suffix中)将作为每个子请求的查询字符串传递,以及原始客户端 URI 中的任何其他查询字符串参数。对于查询字符串样式的请求,来自客户端请求的查询字符串将作为每个子请求的查询字符串传递。

调用是按照它们在键值存储中列出的顺序进行的,但是是异步的,因此响应可以按照任何顺序返回。 这些响应将按照接收顺序汇总为一个响应发送给客户端。 以下是 JavaScript 程序的最小版本:

具有更广泛的错误处理、日志记录和注释功能的 JavaScript 程序版本可在 GitHub Gist repo 中作为batch-api.js获得。

最小 NGINX Plus 配置

以下 NGINX Plus 配置使用一组上游服务器实现了上面讨论的两种请求样式。 为了简单起见,此配置假定上游服务器能够将形式为/myapi/ service / item# (最终元素样式)的调用转换/myapi/service.php/?item=item# (查询字符串样式),这是 PHP 的“本机”URI 格式,PHP 是我们的示例目录、库存和评论服务的语言。

有关执行翻译本身的更广泛的 NGINX Plus 配置,请参阅下面的扩展 NGINX 配置以翻译 URI

让我们逐部分查看配置文件,并解释每个部分的作用:

  • 导入JavaScript 文件

  • 定义一个键值存储来保存 API 请求列表,其中 URI 的最后一个元素标识 API 程序的参数。 该键使用$uri_prefix变量来捕获 URI 中最后一个/之前的部分:

    NGINX Plus R16及更高版本中,您可以利用两个附加的键值功能:

    • 通过将timeout参数添加到keyval_zone指令来设置键值存储中条目的过期时间。 例如,要使每个批处理 URI 每天过期,请添加timeout=1d
    • 通过将sync参数添加到keyval_zone指令,在 NGINX Plus 实例集群中同步键值存储。 在这种情况下,您还必须包括超时参数。

    有关设置键值存储同步的说明,请参阅NGINX Plus 管理指南

  • 为在查询字符串中标识参数的 API 定义另一个键值存储。 此处的键( $uri )捕获整个 URI,不包括查询字符串:

  • 定义两个映射,将 URI 拆分为两部分,用于接受请求的 API,其中参数是 URI 的最后一个元素。 $uri_prefix变量捕获最后一个 / 之前的 URI 元素,而$uri_suffix捕获最后一个元素:

  • 定义上游 API 服务器组(这里,它们与 NGINX Plus 一起在 localhost 上运行):

  • 定义处理客户端请求和子请求的虚拟服务器

  • 定义一个位置来处理使用 final‑element 样式的客户端请求,通过将$batch_api_arg_in_uri变量设置为on来向batchAPI函数指示该位置:

  • 定义一个位置来处理使用查询字符串样式的客户端请求,通过将$batch_api_arg_in_uri变量设置为off来向batchAPI函数指示该位置:

  • 定义处理子请求的位置:

  • 启用NGINX Plus API ,以便可以在键值存储中维护数据:

完整配置如下:

配置批量 API 请求

我们正在使用 NGINX Plus 键值存储功能将入站客户端请求映射到一组要执行的 API 请求。 上一节中的配置为两种请求样式定义了单独的键值存储:

  • 最终元素样式的键值存储名为batch_api ,键是$uri_prefix变量,它捕获请求 URI 的最后一个/之前的元素。
  • 查询字符串样式的键值存储名为batch_api2 ,键是$uri变量,它捕获没有查询字符串的完整请求 URI。

在这两个键值存储中,与每个键关联的值都是以逗号分隔的 URI 列表,这些 URI 在运行时在$batch_api$batch_api2变量中可用。

对于 final‑element 样式的请求,我们希望将客户端对/batch-api/product 的请求映射到对三个服务/myapi/catalog/myapi/inventory/myapi/review 的请求,这样对/batch-api/product/14286 的请求将导致对/myapi/catalog/14286/myapi/product/14286/myapi/review/14286 的请求。

为了将这些映射添加到batch_api键值存储,我们向本地机器上运行的 NGINX Plus 实例发送以下请求:

$ curl -iX POST -d '{"/batch-api/product":"/myapi/catalog,/myapi/inventory,/myapi/review"}' http://localhost/api/3/http/keyvals/batch_api

对于查询字符串样式的请求,我们希望将客户端对/batch-api2/product的请求映射到对三个服务/myapi/catalog.php/myapi/inventory.php/myapi/review.php的请求,这样对/batch-api2/product?item=14286 的请求将导致对/myapi/catalog?item=14286/myapi/product?item=14286/myapi/review?item=14286 的请求。

为了将这些映射添加到batch_api2键值存储,我们发送此请求:

$ curl -iX POST -d '{"/batch-api2/product":"/myapi/catalog.php,/myapi/inventory.php,/myapi/review.php"}' http://localhost/api/3/http/keyvals/batch_api2

运行示例

相同的 PHP 页面处理两种请求样式的请求。 为简单起见,我们假设后端服务器能够将最终元素样式 URI( /myapi/ service / item# )转换为查询字符串样式 URI( /myapi/service.php?item=item# 。 没有必要翻译查询字符串样式的 URI,因为这是 PHP 程序的“本机”URI 格式。

所有服务都返回包含服务名称和项目参数的 JSON 格式的响应。 例如,对/myapi/catalog.php?item=14286的请求会导致catalog.php产生以下响应:

{"服务":"目录","商品":"14286"}

尽管这些示例中使用的 PHP 程序在响应中包含了服务名称,但并非所有服务都是如此。 为了帮助将响应与生成它们的服务进行匹配,JavaScript 程序将 URI 包含在聚合响应中。

例如,对/batch-api/product/14286请求的聚合响应如下(尽管三个组件响应的顺序可能有所不同):

[["/myapi/review/14286",{"service":"评论","item":"14286"}],["/myapi/inventory/14286",{"service":"库存","item":"14286"}],["/myapi/catalog/14286",{"service":"目录","item":"14286"}]]

扩展 NGINX Plus 配置以翻译 URI

如上所述,上面讨论的最小 NGINX Plus 配置假定 API 服务器能够将格式为/myapi/ service / item#的 URI 转换为/myapi/ service .php/?item= item# 。 我们还可以通过进行以下更改在NGINX Plus配置中实现翻译。

  • 添加一个新的上游组来接收子请求:

  • 添加一个新的虚拟服务器来监听服务上游组收到的请求。 当收到查询字符串样式的请求时,它们只是被代理到api_servers上游组,因为 URI 已经具有.php扩展名。 当收到最终元素样式请求时,将重写 URI,以便删除 URI 中的最后一个元素并将其转换为查询字符串参数:

  • /myapi位置更改为代理到新的上游组:

完整配置如下:

其他组件

示例 JavaScript 程序和 NGINX Plus 配置可以适应其他风格的 API,但如果您想使用创建此博文所用的所有组件进行测试,它们可以在 GitHub 上的 Gist repo 中找到,包括用于提供 PHP 页面的 NGINX Unit 配置:

batch-api.js
目录.php
库存.php
审查.php
单元配置

结论

这些示例展示了如何批处理 API 请求并向客户端提供聚合响应。 NGINX Plus 键值存储允许我们通过NGINX Plus API动态配置 API 请求。API 系统在具体操作上差异很大,因此可以对此示例进行许多增强,以满足特定 API 的需求。

您可以开始使用NGINX Open Source测试 NGINX JavaScript 子请求,但如果您想尝试 API 批处理示例或测试利用 NGINX Plus 功能(如键值存储和NGINX Plus API)的其他用例,请申请30 天免费试用并开始试验。


“这篇博文可能引用了不再可用和/或不再支持的产品。 有关 F5 NGINX 产品和解决方案的最新信息,请探索我们的NGINX 产品系列。 NGINX 现在是 F5 的一部分。 所有之前的 NGINX.com 链接都将重定向至 F5.com 上的类似 NGINX 内容。”