微服务架构下RESTful风格api实践中,我为何抛弃了路由参数 - 用简单设计来提速

本文涉及的产品
资源编排,不限时长
无影云电脑个人版,1个月黄金款+200核时
无影云电脑企业版,4核8GB 120小时 1个月
简介: 本文探讨了 RESTful API 设计中的两种路径方案:动态路径和固定路径。动态路径通过路径参数实现资源的 CRUD 操作,而固定路径则通过查询参数和不同的 HTTP 方法实现相同功能。固定路径设计提高了安全性、路由匹配速度和 API 的可维护性,但也可能增加 URL 长度并降低表达灵活性。通过对比测试,固定路径在性能上表现更优,适合微服务架构下的 API 设计。

在如今关于 RESTful API 的实践中,许多设计示例经常遵循类似以下的动态路径方案:

方案一:动态路径

方法 路径 描述
GET /zoos 列出所有的动物园
POST /zoos 新增一个新的动物园
GET /zoos/{zoo} 获取指定动物园详情
PUT /zoos/{zoo} 更新指定动物园
DELETE /zoos/{zoo} 删除指定动物园
GET /zoos/{zoo}/animals 检索指定动物园下的动物列表
GET /animals 列出所有动物

这种设计已经成为许多 RESTful 服务器的主流。然而,仔细研究 RESTful 的核心思想会发现,它并没有强制要求这样的设计,仅仅是建议将服务资源化,并结合 HTTP 方法(而不是仅仅使用 POST)来实现 API 的统一化。比如对于动物园的 API,如果按照以前的设计可能会有 getZooListupdateZoodeleteZoo 等函数,而资源化之后,主路径只有一个 /zoos,利用不同的 HTTP 方法实现 CRUD 操作。

那么这么做的目的是什么呢?

主要目的是利用 HTTP 的语义来简化和统一 API 的设计。然而,动态路径参数的使用却在无形中增加了路由的复杂度,并没有充分利用单个端点的功能。

如果去掉路由参数,上述 API 可以转化为:

方案二:固定路径

方法 路径 描述
GET /zoos 获取动物园索引(批量查询)
GET /zoo?zoo=123&zoo=111 查询指定动物园的信息
POST /zoo 新增一个动物园
PUT /zoo 更新一个动物园(信息在请求体中)
DELETE /zoo 删除某个动物园
GET /zoo/animals?zoo=123 查询某个动物园的动物列表(批量)
GET /animals 列出所有动物

这种改动的优点是什么?

  1. 安全性提高:动态路由参数需要使用正则匹配路径,容易受到正则匹配攻击——利用特殊参数让正则陷入死循环或耗费大量资源。而固定路径只需简单的路径到处理函数的映射,可以有效避免这类问题。

  2. 路由匹配加速:不使用路由参数时路由匹配速度会提升 50%。这种改动降低了路由匹配的复杂度,使请求的解析速度更快,在高并发情况下能够显著提高系统的性能和用户体验。

  3. API 包装和复用:可以更充分地利用固定路径的不同 HTTP 方法。前端不需要拼接复杂的路径,查询参数可以统一封装成 API 工具套件,简化增删改查的调用逻辑。

  4. ID 安全性:路径中的 ID 信息直接暴露存在安全隐患,尤其是用户 ID 等敏感信息。如果将这些信息全部放在请求体中,并通过 HTTPS 传输,至少不会直接暴露在 URL 中。

  5. 与 RPC 的对接更方便:这种设计模式可以更方便地与 RPC(如 WebSocket)等端点对接。固定路径使得 API 的调用方式更加稳定,与长连接的接口集成也更加简便。

  6. 减少错误可能性:去掉路径参数减少了一个出错的维度,降低了 API 设计的复杂性,减少了开发人员在路径匹配和参数处理方面的工作量。

  7. 统一的日志与监控:在固定路径下,所有相同类型的请求路径一致,更便于日志的查询与监控规则的统一配置。统一的路径格式可以更方便地对同类型请求进行聚合统计和异常检测。

  8. 简化权限控制:由于路径固定,权限控制逻辑可以更加简单和集中,减少了基于不同路径的复杂权限校验。统一的路径形式使得权限策略更加清晰和可维护,尤其在涉及到多个服务之间的协作时,权限控制可以统一而不混乱。

  9. 减少文档复杂度:固定路径的设计可以减少 API 文档的复杂度。每个路径的用途更加明确,开发人员可以更快地理解 API 的使用方式,减少了对 API 文档的误解和困惑,从而提高开发效率。

这种改动的缺点是什么?

  1. URL 变长:固定路径可能会增加 URL 的长度,但如果因此超过了限制,可能需要重新审视设计,明确查询参数的含义。例如,将令牌等敏感信息放在查询参数中显然是错误的做法。长路径可能会对某些设备或浏览器产生影响,但可以通过合理设计参数结构来缓解这个问题。

  2. 表达灵活性降低:动态路径有助于直接体现资源之间的层次关系,而固定路径有时会使 URL 看起来不够直观,不便于人类阅读。尤其在涉及到复杂资源关系时,动态路径可以更直观地展示资源的从属和层级关系,而固定路径可能显得过于扁平。

  3. 对部分开发者习惯的改变:许多开发者习惯了动态路径的 RESTful 风格,固定路径可能需要开发团队对现有思维方式进行调整。一些工具和框架也对动态路径有较好支持,这种改变可能需要重新配置和调整工具链。

具体例子对比

  • 动态路径方案

    • 获取某个动物园下的动物:GET /zoos/123/animals
    • 优点:路径层次清晰,表达资源关系。开发人员可以很容易理解资源之间的关系,尤其在浏览器中查看时更加直观。
  • 固定路径方案

    • 获取某个动物园下的动物:GET /zoo/animals?zoo=123
    • 优点:统一路径结构,减少正则匹配的风险。通过统一的路径模式,降低了后端对请求的复杂处理需求,同时简化了前后端的协作。

关于缓存的担忧

浏览器端缓存通常是基于完整路径匹配,因此对这种改动几乎没有影响。对于其他资源的缓存,可以根据需要进行相应设置。例如,可以根据请求的参数配置缓存策略,避免缓存冲突。对于固定路径的请求,缓存策略也可以更加稳定和一致,因为路径形式不会频繁变化,这使得缓存管理变得更加可预测和可靠。

简单的benchmark测试

通过一个路由表+Nodejs的http库实现了一个简单的restful框架

  private routes: Map<string, {
    [method: string]: RequestHandler }>;
  private server: http.Server | null = null;
  register(path: string, method: string, handler: RequestHandler): void
  listen(port: number):void
  private async handleRequest(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>

并与express进行了对比,可以看到速度提升不少,而且传输的数据也少很多
SimpleAPI Results:
Requests/sec: 2827.9
Latency: 375.42 ms
Throughput: 455116.8 bytes/sec

Express Results:
Requests/sec: 2365.34
Latency: 471.91 ms
Throughput: 565120 bytes/sec

总结

抛弃动态路由参数,改为固定路径的设计,可以简化微服务 API 的实现,提高安全性和可维护性,并更好地与其他系统进行对接。在微服务架构下,API 的清晰简洁显得尤为重要,而固定路径的设计理念则提供了一种更加一致和直观的方式来构建 RESTful API。这种设计不仅提高了系统的安全性,还使得 API 的管理和维护变得更加高效。

另外如果和fastify的预定义jsonschema加速json数据解析,速度能够更快吧,非常适合serverless场景应用。

相关文章
|
3天前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
21 1
|
6天前
|
JSON 缓存 JavaScript
深入浅出:使用Node.js构建RESTful API
在这个数字时代,API已成为软件开发的基石之一。本文旨在引导初学者通过Node.js和Express框架快速搭建一个功能完备的RESTful API。我们将从零开始,逐步深入,不仅涉及代码编写,还包括设计原则、最佳实践及调试技巧。无论你是初探后端开发,还是希望扩展你的技术栈,这篇文章都将是你的理想指南。
|
2天前
|
XML JSON 缓存
深入理解RESTful API设计原则与实践
在现代软件开发中,构建高效、可扩展的应用程序接口(API)是至关重要的。本文旨在探讨RESTful API的核心设计理念,包括其基于HTTP协议的特性,以及如何在实际应用中遵循这些原则来优化API设计。我们将通过具体示例和最佳实践,展示如何创建易于理解、维护且性能优良的RESTful服务,从而提升前后端分离架构下的开发效率和用户体验。
|
3天前
|
JSON 缓存 测试技术
构建高效RESTful API的后端实践指南####
本文将深入探讨如何设计并实现一个高效、可扩展且易于维护的RESTful API。不同于传统的摘要概述,本节将直接以行动指南的形式,列出构建RESTful API时必须遵循的核心原则与最佳实践,旨在为开发者提供一套直接可行的实施框架,快速提升API设计与开发能力。 ####
|
4天前
|
消息中间件 运维 开发者
后端开发中的微服务架构实践与挑战####
本文深入探讨了微服务架构在后端开发中的应用,从其核心概念、设计原则到实际部署过程中面临的挑战进行了全面剖析。不同于传统的单体应用,微服务通过将复杂系统拆解为一系列小型、独立的服务,提高了系统的灵活性和可维护性。然而,这种架构的转变也伴随着服务间通信、数据一致性、部署复杂性等新问题。本文旨在为开发者提供一套应对这些挑战的策略,同时分享一些成功案例,以期促进微服务架构的有效实施。 ####
|
6天前
|
缓存 负载均衡 API
后端开发中的微服务架构实践与挑战####
在数字化转型的浪潮中,微服务架构凭借其高度的可扩展性、灵活性及易于维护的特点,成为众多企业后端开发的首选架构模式。本文将深入探讨微服务架构的核心理念,通过具体案例分析其在实际应用中的实践策略与面临的挑战,为读者提供一份详尽的微服务架构实施指南。 ####
|
7天前
|
监控 持续交付 API
深入理解微服务架构:从设计原则到实践应用
深入理解微服务架构:从设计原则到实践应用
|
8天前
|
消息中间件 负载均衡 测试技术
后端开发中的微服务架构实践与挑战####
本文旨在探讨微服务架构在后端开发中的应用实践,深入分析其带来的优势与面临的挑战。通过剖析真实案例,揭示微服务转型过程中的关键技术决策、服务拆分策略、以及如何有效应对分布式系统的复杂性问题。文章还将提供一套评估企业是否适合采用微服务架构的框架,帮助读者更好地理解这一架构模式,并为企业的技术选型提供参考。 ####
|
7天前
|
运维 监控 安全
深入理解微服务架构:设计原则、挑战与实践
深入理解微服务架构:设计原则、挑战与实践
|
9天前
|
存储 API 数据库
使用Python和Flask构建简单的RESTful API
使用Python和Flask构建简单的RESTful API