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

本文涉及的产品
资源编排,不限时长
无影云电脑企业版,4核8GB 120小时 1个月
无影云电脑个人版,1个月黄金款+200核时
简介: 本文探讨了 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场景应用。

相关文章
|
1天前
|
Kubernetes 负载均衡 Docker
构建高效后端服务:微服务架构的探索与实践
【10月更文挑战第20天】 在数字化时代,后端服务的构建对于任何在线业务的成功至关重要。本文将深入探讨微服务架构的概念、优势以及如何在实际项目中有效实施。我们将从微服务的基本理念出发,逐步解析其在提高系统可维护性、扩展性和敏捷性方面的作用。通过实际案例分析,揭示微服务架构在不同场景下的应用策略和最佳实践。无论你是后端开发新手还是经验丰富的工程师,本文都将为你提供宝贵的见解和实用的指导。
|
2天前
|
消息中间件 Java API
微服务架构设计与实现:从理论到实践
微服务架构设计与实现:从理论到实践
17 7
|
1天前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。
|
1天前
|
SQL API 数据安全/隐私保护
打造现代化后端服务:从零到一实现RESTful API
【10月更文挑战第20天】在数字化时代的浪潮中,构建一个高效、可靠的后端服务是每个软件工程师的必备技能。本文将引导你理解RESTful API的设计哲学,并通过实际的代码示例,展示如何从无到有地实现一个现代化的后端服务。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的知识和启发。
|
2天前
|
Kubernetes 监控 开发者
专家级实践:利用Cloud Toolkit进行微服务治理与容器化部署
【10月更文挑战第19天】在当今的软件开发领域,微服务架构因其高可伸缩性、易于维护和快速迭代的特点而备受青睐。然而,随着微服务数量的增加,管理和服务治理变得越来越复杂。作为阿里巴巴云推出的一款免费且开源的开发者工具,Cloud Toolkit 提供了一系列实用的功能,帮助开发者在微服务治理和容器化部署方面更加高效。本文将从个人的角度出发,探讨如何利用 Cloud Toolkit 来应对这些挑战。
16 2
|
2天前
|
运维 监控 API
后端开发中的微服务架构实践与挑战####
【10月更文挑战第19天】 本文将深入浅出地探讨微服务架构在后端开发中的应用,通过实例解析其核心理念、优势所在,以及实施过程中可能遭遇的挑战与应对策略。不同于传统单体应用,微服务以其轻量级、灵活性和可扩展性受到青睐,但同时也带来了服务间的通信复杂性、数据一致性等问题。通过本篇文章,读者将对微服务架构有一个全面而深入的理解,为实际项目中的选型与实施提供参考。 ####
|
3天前
|
Kubernetes 持续交付 Docker
探索DevOps实践:利用Docker与Kubernetes实现微服务架构的自动化部署
【10月更文挑战第18天】探索DevOps实践:利用Docker与Kubernetes实现微服务架构的自动化部署
22 2
|
2月前
|
安全 应用服务中间件 API
微服务分布式系统架构之zookeeper与dubbo-2
微服务分布式系统架构之zookeeper与dubbo-2
|
2月前
|
负载均衡 Java 应用服务中间件
微服务分布式系统架构之zookeeper与dubbor-1
微服务分布式系统架构之zookeeper与dubbor-1
|
3月前
|
Kubernetes Cloud Native Docker
云原生之旅:从容器到微服务的架构演变
【8月更文挑战第29天】在数字化时代的浪潮下,云原生技术以其灵活性、可扩展性和弹性管理成为企业数字化转型的关键。本文将通过浅显易懂的语言和生动的比喻,带领读者了解云原生的基本概念,探索容器化技术的奥秘,并深入微服务架构的世界。我们将一起见证代码如何转化为现实中的服务,实现快速迭代和高效部署。无论你是初学者还是有经验的开发者,这篇文章都会为你打开一扇通往云原生世界的大门。

热门文章

最新文章