您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

如何循序渐进地管理RESTful API的生命周期?

时间:2022-08-29 15:43:17  来源:  作者:鸨哥学Java

设计一个直观且用户友好的RESTful API往往是一项艰巨的工作。而对于初次尝试规划和管理API生命周期的新手开发者而言,尤为如此。下面,我将以简单示例的形式,和您探讨如何循序渐进地管理RESTful API的生命周期。

 

初始阶段

让我们首先来看一个典型的Hello应用代码的示例:

> curl http://org. apisix/hello
Hello world
> curl http://org. apisix/hello/Joe
Hello Joe

如下图所示,我们不必了解其底层技术,只需专注其API部分即可。

 

采用API网关

首先也是最关键的一步:禁止将应用直接暴露到互联网上,并在前端建立一个API网关。维基百科是这样定义API网关的:作为一个API的服务器前端,它能够收到各种API请求,并通过实施节流和安全策略,将请求传递给后端服务,进而将响应回传给请求者。

网关通常包括一个用于编排和修改请求与响应转换引擎。同时,网关还可以提供诸如:收集分析数据、提供缓存、支持身份验证、授权、安全审计以及合规检查等功能。当然,如果您不太熟悉API网关的概念,也可以直接把它理解为一个更高级别的反向代理。在此,我将使用 Apache APISIX​ ​,您也可以使用自己熟悉的网关。

为了暴露网关,您需要更新指向网关的DNS记录,并向外广播。您既可以等待一段时间让其自动更新,也可以通过​ ​dnschecker​ ​来加速这个过程。

我使用APISIX创建了一个将HTTP请求发送到网关的路由(route,请参见如下代码段)。

curl http://apisix:9080/apisix/admin/routes/1 -H 'X-API-KEY: xyz' -X PUT -d ' # 1-2
{
  "name": "Direct Route to Old API",               # 3
  "methods": ["GET"],                              # 4
  "uris": ["/hello", "/hello/", "/hello/*"],       # 5
  "upstream": {                                    # 6
    "type": "roundrobin",                          # 8
    "nodes": {
      "oldapi:8081": 1                             # 7
    }
  }
}'

注释:

1. APISIX会分配一个自动生成的ID(您也可以使用现成的)。在此,我使用现成的,并使用put将它传递给URL - 1。

2. 通过API key来更新路由。

3. 虽然我们不一定需要命名路由,但它能够让我们更好地对其有所了解。

4. 针对路由的HTTP方法数组。

5. 针对路由的URL数组。

6. 指明后端应用的上游(upstream)。在本例中,即为Hello World API。

7. 各个节点的Hashmap都自带有权重。显然,权重只有存在多个节点时才有意义。

8. 针对多个节点配置均衡算法。

 

如上图所示,您可以通过如下方式查询网关,并得到相同的结果:

> curl http://org. apisix/hello
Hello world
> curl http://org. apisix/hello/Joe
Hello Joe

API的版本

开发一个API往往意味着会出现其多个版本共存的情况。我们可以用如下三种方式给API编制版本:

  • 查询参数:

curl http://org. apisix/hello?version=1

curl http://org. apisix/hello?version=2

  • 标头:

curl -H 'Version: 1' http://org. apisix/hello

curl -H 'Version: 2' http://org. apisix/hello

  • 路径:

curl http://org. apisix/v1/hello

curl http://org. apisix/v2/hello

在此,我将使用目前广为采用的基于路径的版本编制方法。当然,APISIX也支持其他两种方式。

在前文中,我们创建了一个包含上游信息的路由。同时,APISIX也允许我们创建一个带有专属ID的上游,以重用其多个路由:

curl http://apisix:9080/apisix/admin/upstreams/1 -H 'X-API-KEY: xyz' -X PUT -d ' # 1
{
  "name": "Old API",                                                             # 2
  "type": "roundrobin",
  "nodes": {
    "oldapi:8081": 1
  }
}'

注释:

1. 使用upstreams路径

2. 针对新的上游的有效载荷

由于上游只知道/hello,不知道/v1/hello,因此在转发至上游之前,我们仍需要重写发往网关的查询。APISIX可以通过插件来实现此类转换和过滤。下面,让我们创建一个用于重写路径的插件配置:

curl http://apisix:9080/apisix/admin/plugin_configs/1 -H 'X-API-KEY: xyz' -X PUT -d ' # 1
{
  "plugins": {
    "proxy-rewrite": {                                        # 2
      "regex_uri": ["/v1/(.*)", "/$1"]                        # 3
    }
  }
}'

注释:

1. 使用plugin-configs路径

2. 使用​ ​proxy-rewrite​ ​插件

3. 删除版本的前缀

现在我们就可以通过如下代码段,创建有版本的路由,以引导新创建的上游和插件配置:

curl http://apisix:9080/apisix/admin/routes/2 -H 'X-API-KEY: xyz' -X PUT -d '  # 1
{
  "name": "Versioned Route to Old API",
  "methods": ["GET"],
  "uris": ["/v1/hello", "/v1/hello/", "/v1/hello/*"],
  "upstream_id": 1,
  "plugin_config_id": 1
}'

下面展示了新路由的逻辑图。

 

在此,我们已配置了有版本和非版本的两个路由:

> curl http://org. apisix/hello
Hello world
> curl http://org. apisix/v1/hello
Hello world

将用户从非版本路径迁移到有版本路径

虽然我们给API编制了版本,但是用户可能仍会使用旧的、非版本的API。毕竟,我们肯定不能在用户不知情时就删除掉旧的路由,而只能通过HTTP的301状态代码,让用户知道资源已经从http://org.apisix/hello迁移到了

http://org.apisix/v1/hello。如下代码段展示了​ ​如何通过配置重定向插件​ ​来初始化路由:

curl http://apisix:9080/apisix/admin/routes/1 -H 'X-API-KEY: xyz' -X PATCH -d '
{
  "plugins": {
    "redirect": {
      "uri": "/v1$uri",
      "ret_code": 301
    }
  }
}'

 

其运行结果如下:

>curl http://apisix. org/hello
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>openresty</center>
</body>
</html>
>curl -L apisix:9080/hello                     # 1
Hello world

注释:

1. -L选项后面跟着重定向

根据规则,用户要么透明地使用到了新的端点,要么收到301的状态提示,使用新的API位置。

识别用户

您可能已经注意到,我们并不知道谁会使用我们的API。因此,为了保证API在被调用的过程中不会中断用户的使用,我选择了限制未注册的用户可调用的数量。如果他们的总量到达了该限制,我们将返回典型的HTTP 429状态消息,要求他们完成注册。

当然,目前尚无开箱即用的插件可以实现这一点。因此,我在APISIX中引入Lua引擎,并用Lua编写出了相应的插件。您可以通过GitHub的链接

--https://github.com/nfrankel/evolve-apis/blob/master/unauth-limit-plugin/src/unauth-limit.lua,来浏览其源代码。当然,您也可以使用Python/ target=_blank class=infotextkey>Python、WebAssembly或任何基于JVM的语言,来编写自己的插件。

我将通过如下步骤来完成插件的加载:

1. 配置APISIX使用的目录:

apisix: extra_lua_path:/opt/apisix/.lua ?”

注意:APISIX可以使用位于/opt/apisix/文件夹下的任何Lua脚本。

2. 加载插件:

由于APISIX支持热重载,因此它可以在无需重新启动的情况下添加额外的插件。

curl http://apisix:9080/apisix/admin/plugins/reload -H 'X-API-KEY: xyz' -X PUT

3. 给现有插件的配置打补丁:

最后,我们需要为插件本身更新专属的配置:

curl http://apisix:9080/apisix/admin/plugin_configs/1 -H 'X-API-KEY: xyz' -X PATCH -d '
{
  "plugins": {
    "proxy-rewrite": {                                # 1
      "regex_uri": ["/v1/(.*)", "/$1"]
    },
    "unauth-limit": {                                 # 2
      "count": 1,                                     # 3
      "time_window": 60,                              # 3
      "key_type": "var",                              # 4
      "key": "consumer_name",                         # 4
      "rejected_code": 429,
      "rejected_msg": "Please register at https://apisix. org/register to get your API token and enjoy unlimited calls"
    }
  }
}'

注释:

1. 我们需要重复现有的插件配置。当然,APISIX团队正在修复这个bug。

2. 指向我们的插件。

3. 对于已通过认证的用户,插件可限制每60秒超过一个调用。

4. 我会在下一节中解释到。

我们通过如下命令检查其是否能够按预期运行:

>curl apisix:9080/v1/hello
Hello world
>curl apisix:9080/v1/hello
{"error_msg":"Please register at https://apisix. org/register to get your API token and enjoy unlimited calls"}

实际上确实如此。

用户认证

接着,我们需要为消费者(consumer)角色配置一个专属的身份验证插件。目前,我们可以选用的此类身份验证插件有:API key、JWT、OpenId、LDAP、以及Keycloak等。在本例中,我们采用APISIX的​ ​key-auth​ ​插件。下面,让我们配置一个通过API key验证的消费者对象:

curl http://apisix:9080/apisix/admin/consumers -H 'X-API-KEY: xyz' -X PUT -d '
{
  "username": "johndoe",                 # 1
  "plugins": {
    "key-auth": {                        # 2
      "key": "mykey"                     # 3
    }
  }
}'

注释:

1. 消费者的ID

2. 可供使用的插件

3. 有效令牌--mykey

注意,其默认的标头为apikey,你也可以配置为其他,具体请参见key-auth插件的​ ​相关文档​ ​。

我们用如下命令来验证其是否能够按照我们的需求运行:

>curl -H 'apikey: mykey' apisix:9080/v1/hello
Hello world
>curl -H 'apikey: mykey' apisix:9080/v1/hello
Hello world

在生产环境中测试

至此,我们的改进版Hello world API便可以供用户调用了。如您所见,部署一个新的、可能包含潜在错误的应用版本,往往会给生产环境和业务营收带来负面的影响。为了尽量减少此类风险,我们可以采用金丝雀发布策略,即:先对一小部分用户推出新的软件版本,然后慢慢地扩展到生产环境中的所有用户处。如果出现了故障,那么新版本只会影响一小部分的用户群,我们能够及时回滚到旧的版本。就API网关而言,我们可以复制生产环境的流量到新的API端点上,实现在对用户几乎不产生影响的情况下,尽早发现更多的缺陷。

在此,APISIX提供了​ ​proxy-mirror插件​ ​,可向其他节点发送复制的生产环境流量。对此,我们可以对插件配置做如下更新:

curl http://apisix:9080/apisix/admin/plugin_configs/1 -H 'X-API-KEY: xyz' -X PATCH -d '
{
 "plugins": {
    "proxy-rewrite": {
      "regex_uri": ["/v1/(.*)", "/$1"]
    },
    "unauth-limit": {
      "count": 1,
      "time_window": 60,
      "key_type": "var",
      "key": "consumer_name",
      "rejected_code": 429,
      "rejected_msg": "Please register at https://apisix. org/register to get your API token and enjoy unlimited calls"
    },
    "proxy-mirror": {
      "host": "http://new. api:8082"                             # 1
    }
  }
}'

注释:

1. APISIX将发送流量到该地址上。

 

根据上图,我们可以监控和比较新和旧端点,一旦发生错误,我们便可以修复错误,并重新部署。在此,我们首先通过如下命令,创建一个指向新的API的上游:

curl http://apisix:9080/apisix/admin/upstreams/2 -H 'X-API-KEY: xyz' -X PUT -d '
{
  "name": "New API",
  "type": "roundrobin",
  "nodes": {
    "newapi:8082": 1
  }
}'

然后,我们可以使用​ ​traffic-split​ ​,来更换proxy-mirror插件:

curl http://apisix:9080/apisix/admin/plugin_configs/1 -H 'X-API-KEY: xyz' -X PATCH -d '
{
 "plugins": {
    "proxy-rewrite": {
      "regex_uri": ["/v1/(.*)", "/$1"]
    },
    "unauth-limit": {
      "count": 1,
      "time_window": 60,
      "key_type": "var",
      "key": "consumer_name",
      "rejected_code": 429,
      "rejected_msg": "Please register at https://apisix. org/register to get your API token and enjoy unlimited calls"
    },
    "traffic-split": {
      "rules": [
        {
          "weighted_upstreams": [      # 1
            {
              "upstream_id": 2,
              "weight": 1
            },
            {
              "weight": 1
            }
          ]
        }
      ]
    }
  }
}'

注释:

1. 作为演示,我们将50%的流量发送到新的API。在真实环境中,您可能只会配置少数的内部用户去使用新的端点。

curl -L -H 'apikey: mykey' apisix:9080/hello
Hello world
curl -L -H 'apikey: mykey' apisix:9080/hello
Hello world (souped-up version!)

如果一切工作正常,我们可以将逐渐增加的流量移至新的API。最终我们可以移除traffic split,将默认端点从v1重定到v2上。

弃用旧的版本

根据IETF的草案规范,我们可以基于特定的HTTP响应标头,来弃用HTTP的标头字段 (请参见

--https://tools.ietf.org/id/draft-dalal-deprecation-header-03.html)。即:在API网关的帮助下,我们可以通过配置路由,来与有待弃用和替代的版本进行通信。为此,我们将使用由APISIX提供​ ​response-rewrite​ ​,来添加额外弃用标志标头,请参见如下代码段:

curl -v http://apisix:9080/apisix/admin/plugin_configs/1 -H 'X-API-KEY: xyz' -X PATCH -d '
{
 "plugins": {
    "proxy-rewrite": {
      "regex_uri": ["/v1/(.*)", "/$1"]
    },
    "unauth-limit": {
      "count": 1,
      "time_window": 60,
      "key_type": "var",
      "key": "consumer_name",
      "rejected_code": 429,
      "rejected_msg": "Please register at https://apisix. org/register to get your API token and enjoy unlimited calls"
    },
    "response-rewrite": {
      "headers": {
        "Deprecation": "true",
        "Link": "<$scheme://apisix:$server_port/v2/hello>; rel="successor-version""
      }
    }
  }
}'
curl -v -H 'apikey: mykey' apisix:9080/v1/hello
< HTTP/1. 1 200 
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 11
< Connection: keep-alive
< Date: Fri, 18 Feb 2022 16:33:30 GMT
< Server: APISIX/2. 12. 0
< Link: <http://apisix:9080/v2/hello>; rel="successor-version"
< Deprecation: true
< 
Hello world

小结

回顾一下,我们按照如下流程向您展示了如何通过循序渐进的过程,来管理API的整个生命周期。

1. 不要直接暴露您的API,而是在前端建立一个API网关

2. 使用路径、查询参数、以及请求标头给现有的API编制版本

3. 通过使用301状态码,将用户从无版本的端点迁移到有版本处

4. 识别和认证用户

5. 为了测试生产环境,我们先复制流量,再将小部分用户迁移到新的版本上

6. 发布新的版本

7. 通过标准响应标头来弃用旧的版本



Tags:RESTful   点击:( )  评论:( )
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:[email protected]),我们将及时更正、删除,谢谢。
▌相关推荐
设计一个直观且用户友好的RESTful API往往是一项艰巨的工作。而对于初次尝试规划和管理API生命周期的新手开发者而言,尤为如此。下面,我将以简单示例的形式,和您探讨如何循序渐...【详细内容】
2022-08-29  Tags: RESTful  点击:(0)  评论:(0)  加入收藏
在此前写的文章“从零基础入门进行小程序开发实战”中,已经介绍过背单词的小程序,因为没有备案的服务器资源只能使用系统后台提供的缓存功能存储用户数据。缓存有大小限制,而且...【详细内容】
2021-07-27  Tags: RESTful  点击:(193)  评论:(0)  加入收藏
Facebook、GitHub、Google以及其他许多巨头都需要一种服务和消费数据的方式。在当今的开发环境中,RESTful API仍然是服务和消费数据的最佳选择之一。 但是你是否考虑过学习行...【详细内容】
2020-08-30  Tags: RESTful  点击:(103)  评论:(0)  加入收藏
通过管理一套图书的完整代码示例,来探索轻量级的 RESTful 服务。&bull; 来源:linux.cn &bull; 作者:Marty Kalin &bull; 译者:MCGA &bull;(本文字数:24337,阅读时长大约:28 分钟)Web...【详细内容】
2020-08-27  Tags: RESTful  点击:(81)  评论:(0)  加入收藏
RESTful API无处不在,比任何其他API体系结构都为现代世界提供了更多支持。 根据ProgrammableWeb的研究,REST占API的80%。 这些API的构建和结构方式可以在当今竞争异常激烈的世...【详细内容】
2020-06-21  Tags: RESTful  点击:(66)  评论:(0)  加入收藏
基于一些不错的RESTful开发组件,可以快速的开发出不错的RESTful API,但如果不了解开发规范的、健壮的RESTful API的基本面,即便优秀的RESTful开发组件摆在面前,也无法很好的理...【详细内容】
2020-01-02  Tags: RESTful  点击:(146)  评论:(0)  加入收藏
来自:唐尤华译自:https://dzone.com/refcardz/rest-foundations-restful REST(Representational State Transfer)架构风格是一种世界观,把信息提升为架构中的一等公民。通过 R...【详细内容】
2019-10-21  Tags: RESTful  点击:(304)  评论:(0)  加入收藏
RestFul API 是每个程序员都应该了解并掌握的基本知识,我们在开发过程中设计API的时候也应该至少要满足RestFul API的最基本的要求(比如接口中尽量使用名词,使用POST 请求创建...【详细内容】
2019-08-12  Tags: RESTful  点击:(399)  评论:(0)  加入收藏
▌澳门威斯尼斯人app官方下载推荐
设计一个直观且用户友好的RESTful API往往是一项艰巨的工作。而对于初次尝试规划和管理API生命周期的新手开发者而言,尤为如此。下面,我将以简单示例的形式,和您探讨如何循序渐...【详细内容】
2022-08-29  鸨哥学Java    Tags:RESTful   点击:(0)  评论:(0)  加入收藏
网上有很多人互相讨论:软件测试是否需要掌握编程能力。其实这个问题并不难回答。对于基础的软件测试人员来说,编程能力并非必须的技能,随着测试岗位的变化以及研究能力的逐渐深...【详细内容】
2022-08-28  青烟小生x   网易  Tags:软件测试   点击:(4)  评论:(0)  加入收藏
赶紧收藏一下吧!!!!虽然xjjdog已经写了快400篇原创了,但比起下面推荐的这7个github仓库,真如同是沧海一栗。一个人的头脑很可怕,一堆人的头脑更骇人。这些仓库经过了岁月的沉淀,里面...【详细内容】
2022-08-26  ITPUB2022     Tags:github仓库   点击:(6)  评论:(0)  加入收藏
今天的标题确实是无聊。有些时候,你可能需要进行一项多级计算。最为常见的例子是对一个包含有主版本号和次版本号的版本信息进行检查。错误的版本号检查是最常见的错误来源之...【详细内容】
2022-08-26  漫漫开发路   网易号  Tags:多级比较   点击:(1)  评论:(0)  加入收藏
String vs StringBuffer vs StringBuilder本文翻译自:String vs StringBuffer vs StringBuilder | DigitalOcean 字符串是Java中使用最广泛的类之一。StringBuffer和StringBu...【详细内容】
2022-08-25  愷龍  今日头条  Tags:愷龍   点击:(10)  评论:(0)  加入收藏
时间轮是一个高性能、低消耗的数据结构,它适合用非准实时,延迟的短平快任务,例如心跳检测。在Netty、Kafka、Zookeeper中都有使用。时间轮可通过时间与任务存储分离的形式,轻松...【详细内容】
2022-08-23  鸨哥学Java    Tags:Netty   点击:(7)  评论:(0)  加入收藏
树型结构是比较常规的分类思维方式,好的分类规则能事半功倍,比如文件目录、日常开发的代码,时序图是树型结构的另一种展示形式。这里介绍插件中JTree的基本结构。 JTree对象生...【详细内容】
2022-08-21  木生杨    Tags:Idea   点击:(15)  评论:(0)  加入收藏
其实微软当年的MFC更接近于“代码描述界面”,Delphi等反而是通过专门的配置文件.DFM来描述窗体&hellip;&hellip;比如,这个来自CSDN的截图就是一个典型.DFM文件内容:Delphi项目...【详细内容】
2022-08-21  沈洛书馆    Tags:XML   点击:(18)  评论:(0)  加入收藏
1. 概述 本文介绍了一个简单的嵌入式项目的的开发过程; 从需求到实践,本文对整个过程做了全面的介绍,本文所介绍的设备容易获得且价格低廉; 本文涉及了 *Linux* 下 C 语言下的网...【详细内容】
2022-08-20  whowin1963    Tags:嵌入式   点击:(12)  评论:(0)  加入收藏
工欲善其事必先利其器。对于IT程序员来讲,好用的开发工具可以大大提高开发效率。本文将向大家推荐IT程序员常用的十款开发工具,希望能帮助大家更加优雅地写出代码。这些工具分...【详细内容】
2022-08-18  青烟小生x     Tags:开发工具   点击:(17)  评论:(0)  加入收藏
站内最新
站内热门
站内头条