微服务架构下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场景应用。

相关文章
|
5天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
17天前
|
Java API PHP
阿里巴巴参数获取API
阿里巴巴的参数获取API流程包括:1. 注册并认证开发者账号;2. 创建应用,获取API密钥;3. 阅读API文档,了解请求参数和返回格式;4. 编写代码调用API,如使用Python请求商品详情;5. 注意API类型及其参数,遵守数据使用规则和法律法规。
|
3天前
|
负载均衡 监控 API
dotnet微服务之API网关Ocelot
Ocelot 是一个基于 .NET 的 API 网关,适用于微服务架构。本文介绍了如何创建一个 Web API 项目并使用 Ocelot 进行 API 请求路由、负载均衡等。通过配置 `ocelot.json` 和修改 `Program.cs`,实现对 `GoodApi` 和 `OrderApi` 两个项目的路由管理。最终,通过访问 `https://localhost:7122/good/Hello` 和 `https://localhost:7122/order/Hello` 验证配置成功。
12 1
dotnet微服务之API网关Ocelot
|
6天前
|
运维 Cloud Native 应用服务中间件
阿里云微服务引擎 MSE 及 云原生 API 网关 2024 年 10 月产品动态
阿里云微服务引擎 MSE 面向业界主流开源微服务项目, 提供注册配置中心和分布式协调(原生支持 Nacos/ZooKeeper/Eureka )、云原生网关(原生支持Higress/Nginx/Envoy,遵循Ingress标准)、微服务治理(原生支持 Spring Cloud/Dubbo/Sentinel,遵循 OpenSergo 服务治理规范)能力。API 网关 (API Gateway),提供 APl 托管服务,覆盖设计、开发、测试、发布、售卖、运维监测、安全管控、下线等 API 生命周期阶段。帮助您快速构建以 API 为核心的系统架构.满足新技术引入、系统集成、业务中台等诸多场景需要
|
8天前
|
Prometheus 监控 Java
深入探索:自制Agent监控API接口耗时实践
在微服务架构中,监控API接口的调用耗时对于性能优化至关重要。通过监控接口耗时,我们可以识别性能瓶颈,优化服务响应速度。本文将分享如何自己动手实现一个Agent来统计API接口的调用耗时,提供一种实用的技术解决方案。
17 3
|
11天前
|
监控 安全 应用服务中间件
微服务架构下的API网关设计策略与实践####
本文深入探讨了在微服务架构下,API网关作为系统统一入口点的设计策略、实现细节及其在实际应用中的最佳实践。不同于传统的摘要概述,本部分将直接以一段精简的代码示例作为引子,展示一个基于NGINX的简单API网关配置片段,随后引出文章的核心内容,旨在通过具体实例激发读者兴趣,快速理解API网关在微服务架构中的关键作用及实现方式。 ```nginx server { listen 80; server_name api.example.com; location / { proxy_pass http://backend_service:5000;
|
13天前
|
缓存 监控 API
探索微服务架构中的API网关模式
随着微服务架构的兴起,API网关成为管理和服务间交互的关键组件。本文通过在线零售公司的案例,探讨了API网关在路由管理、认证授权、限流缓存、日志监控和协议转换等方面的优势,并详细介绍了使用Kong实现API网关的具体步骤。
34 3
|
13天前
|
存储 缓存 监控
探索微服务架构中的API网关模式
探索微服务架构中的API网关模式
31 2
|
16天前
|
XML API 网络架构
深入理解RESTful API设计原则与实践
【10月更文挑战第26天】在数字化浪潮中,API(应用程序编程接口)成为连接不同软件组件的桥梁。本文将深入浅出地探讨如何根据REST(Representational State Transfer)原则设计高效、易于维护和扩展的API,同时分享一些实用的代码示例,帮助开发者构建更加健壮和用户友好的服务。
|
16天前
|
监控 测试技术 API
确保微服务的API版本控制策略能够适应不断变化的业务需求
确保微服务的API版本控制策略能够适应不断变化的业务需求