Google语音识别技术详解与实践应用
掌握 .NET Web API:构建强大 API 的最佳实践
通过阅读这篇内容丰富的大师级文章,您可以掌握dotnet Web API的构建方法,并运用最佳实践来打造强大的API。
介绍
开发 API 时,程序员除了实现基本功能之外还需要考虑各种因素。他们必须解决版本控制、安全性、性能、错误处理和文档等问题。通过整合这些领域的最佳实践,程序员可以确保其 API 的可靠性、可扩展性和可用性。
本文旨在全面概述程序员在创建 API 时应遵循的最佳实践。不论是使用.NET 6 Web API还是其他任何框架,这些实践对于打造设计优良且功能强大的API都至关重要。
对 API 进行版本控制
什么是 API 版本控制?
API 版本控制是一种用于管理 API 更改同时保持现有客户端向后兼容性的技术。它赋予了开发人员引入新功能、修复错误或对API进行其他修改的能力,同时不会影响到现有的集成功能。
API是软件。软件的每个部分都需要在某个时候进行更新。在您的API上进行更新时,需要确保所做的更改不会影响到API的使用者(用户)。为了确保这一点,您需要引入API 版本控制。
为什么需要 API 版本控制?
您需要 API 版本控制,因为它可以确保兼容性、支持灵活地采用更改、提供受控和记录的修改、支持多个版本共存以及对 API 生命周期进行精细控制,从而实现成功且高效的软件开发。
如果您的目标是开发健壮且可扩展的 Web 应用程序,请考虑雇用Toptal 的ASP.NET 开发人员。凭借在构建高性能解决方案方面深厚的专业知识,Toptal的ASP.NET专家能够开发出满足复杂业务需求的前沿应用程序,助力顶级企业和初创公司高效达成其技术目标。
最重要的3个原因:
- 向后兼容性:它确保客户端可以继续使用旧版本,而新客户端可以利用更新的功能。
- API 演变:随着API随时间不断演变,版本控制使得您能够引入新功能、弃用旧功能,并在不影响现有客户端的情况下进行改进。
- 客户端灵活性:不同的客户端可能有不同的要求,或者可能需要特定版本的 API 中提供的特定功能。
ASP.NET Web API 版本控制
.NET 6 中有多种 API 版本控制方法。以下是常用的一种方法:
- 基于标头的版本控制:版本号在 HTTP 请求的自定义标头中指定。例如:
GET /products HTTP/1.1
Host: api.example.com
Accept: application/json
X-API-Version: 2
我们以基于 URL 为例。首先,您需要安装一个包:Microsoft.AspNetCore.Mvc.Versioning
然后您需要在 Program.cs C# class 中配置 API 版本控制:
Program.cs C# class:builder.Services.AddApiVersioning(options =>
{
options.ReportApiVersions = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ApiVersionReader = new UrlSegmentApiVersionReader();
});
– ReportApiVersions -> API 响应将包含有关可用版本和当前请求使用的版本的信息
– DefaultApiVersion -> 此选项设置默认 API 版本。
– AssumeDefaultVersionWhenUnspecified -> 当将其设置为true时,如果客户端在发出的请求中未包含版本号,那么API将会采用在DefaultApiVersion中预先设定的默认版本来进行处理。
– ApiVersionReader -> 它确定如何从请求中提取 API 版本。在这种情况下,API 版本是从 URL 段中读取的。
在Products Controller
中,您可以通过使用MapToApiVersion
属性来修饰操作方法,从而明确指定每个方法所对应的版本。
客户端可以通过将版本号附加到 URL 来访问不同版本的 API,例如/v1/products或/v2/products。
[ApiController]
[Route("v{version:apiVersion}/products")]
public class ProductsController : ControllerBase
{
// GET v1/products
[HttpGet]
[MapToApiVersion("1.0")]
public IActionResult GetV1()
{
// Implementation for version 1
}
// GET v2/products
[HttpGet]
[MapToApiVersion("2.0")]
public IActionResult GetV2()
{
// Implementation for version 2
}
}
根据我的经验,采用基于属性的路由能够更轻松地实现配置与组织,确保版本控制策略的一致性,对每个版本进行详尽记录以便用户了解,同时优先考虑向后兼容性,从而避免对现有用户造成任何干扰。
相信我,遵循这些技巧将使您在 .NET 6 中的 API 开发变得轻而易举!
使用正确的 HTTP 方法
什么是 HTTP 方法?
HTTP 方法,也称为HTTP 动词,是可以使用超文本传输协议 (HTTP) 对资源执行的标准化操作。这些方法定义了对客户端请求的特定资源执行的操作类型。
最常用的方法是:
- GET:检索资源的表示。
- POST:创建新资源。
- PUT:如果不存在,则创建新资源;如果已存在,则更新现有资源。
- PATCH:部分更新现有资源。
- DELETE:删除资源。
为什么使用正确的 HTTP 方法很重要?
使用正确的 HTTP 方法非常重要,因为它可以确保遵守 REST 架构风格的原则,改进 API 设计和可维护性,通过实施适当的访问控制来增强安全性,促进可扩展性和缓存机制,并实现与各种客户端和服务器的互操作性和兼容性网络。
在我看来,以下两点是最为重要的:
- RESTful 原则:正确使用 HTTP 方法符合表述性状态传输 (REST) 的原则。 RESTful API 利用这些方法的语义为客户端创建统一且可预测的接口。
- 语义清晰:每个HTTP方法都承载着特定的含义,这使得您的API端点设计得更加直观且易于理解。开发人员可以根据所使用的 HTTP 方法轻松了解端点的用途和功能。
有哪些 HTTP 方法?
- GET:使用 GET 从资源中检索数据。它不应该对服务器产生任何副作用。
- POST:使用 POST 创建新资源。请求有效负载通常包含新资源的数据,并且服务器为其分配唯一标识符。
- PUT:使用PUT方法可以在资源不存在时创建新资源,或者在资源已存在时更新现有资源。请求负载中应包含待更新资源的完整表示。
- PATCH:使用 PATCH 对现有资源执行部分更新。请求负载仅包括需要应用于资源的更改。
- DELETE:使用 DELETE 删除由其唯一标识符标识的资源。
经验:
让我分享一下我在开发 .NET API 时使用 HTTP 方法的有趣经历。这一切都始于我错误地使用“GET”方法而不是“POST”来提交用户数据。这导致了信息的滑稽混淆和混乱。
似乎仅仅这样还不够,当我错误地使用了“PUT”方法而不是“DELETE”方法去删除资源时,我遭遇了一个棘手的问题,导致数据被持久且顽固地留存了下来。
经验教训:务必要始终采用正确的HTTP方法,否则您可能会发现自己陷入一个满是奇怪API的境地!
.NET 6 示例
[ApiController]
[Route("products")]
public class ProductsController : ControllerBase
{
// GET /products
[HttpGet]
public IActionResult Get()
{
// Implementation to retrieve all products
}
// GET /products/{id}
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
// Implementation to retrieve a specific product by ID
}
// POST /products
[HttpPost]
public IActionResult Create(ProductDto product)
{
// Implementation to create a new product using the provided data
}
// PUT /products/{id}
[HttpPut("{id}")]
public IActionResult Update(int id, ProductDto product)
{
// Implementation to update an existing product identified by the ID
}
// PATCH /products/{id}
[HttpPatch("{id}")]
public IActionResult PartialUpdate(int id, JsonPatchDocument<ProductDto> patchDocument)
{
// Implementation to apply partial updates to an existing product
}
// DELETE /products/{id}
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
// Implementation to delete a specific product by ID
}
}
请务必根据要对资源执行的具体操作来选择合适的HTTP方法,并严格遵循每种方法所规定的指南及最佳实践。
保护您的 API
保护 API对于保护敏感数据、防止未经授权的访问以及确保应用程序的完整性至关重要。这个过程涉及实施一系列措施和实践,旨在保护应用程序编程接口(API),防止其遭受未经授权的访问、数据泄露以及其他安全风险。它涉及实施身份验证、授权、加密和其他安全机制,以确保 API 及其处理的数据的机密性、完整性和可用性。
在开发.NET 6 Web API时,有几个关于API安全性的重要方面需要我们考虑。
身份验证:
实施身份验证对于防止未经授权的访问和保护敏感资源至关重要。在 .NET 6 Web API 中,您可以利用各种身份验证机制,例如JSON Web 令牌 (JWT)、OAuth或自定义身份验证方案。
.NET 6 中的 JWT 不记名令牌示例:
// Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "your_issuer",
ValidAudience = "your_audience",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("your_security_key"))
};
});
}
授权
实施授权可确保用户对特定 API 端点或资源拥有适当的访问权限。在.NET 6 Web API中,您可以通过使用[Authorize]等授权属性,或者采用基于策略的授权方式,来控制对资源的访问。
// ProductsController.cs
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
[HttpGet]
[Authorize(Roles = "admin")]
public IActionResult GetProducts()
{
// Implementation for retrieving products
}
[HttpPost]
[Authorize]
public IActionResult CreateProduct(ProductDto product)
{
// Implementation for creating a new product
}
}
速率限制
速率限制有助于防止滥用、流量过多和拒绝服务 (DoS) 攻击。它旨在确保API资源得到公平合理的使用,并防止其遭受过度请求的淹没。为实现这一目标,可以在API中运用速率限制技术,例如为每个客户端、IP地址或全局范围设定最大的请求数量限制。
在 .NET 6 中,您可以使用AspNetCoreRateLimit库来实现此目的。
在Program.cs文件中添加依赖项:
services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
并设置中间件:
app.UseIpRateLimiting();
您可以在 appsettings.json 文件中配置速率限制规则:
{
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIpHeader": "X-Forwarded-For",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 5
}
]
}
}
缓存响应
什么是响应缓存?
响应缓存涉及存储 API 请求的响应,并在再次发出相同请求时直接从缓存提供响应。通过缓存响应,您可以减少多次重新处理同一请求的需要,从而缩短响应时间并提高可扩展性。
为什么要使用响应缓存?
您应该使用响应缓存来最大限度地提高 API 的性能和可扩展性,通过减少响应时间来增强用户体验,提高整体响应能力,减轻服务器负载,优化网络带宽消耗并确保可用性,最终形成高效且高性能的 API系统。
我将结合我的经验,向您阐述三个最有说服力的原因:
- 改进的性能:无需重复执行相同的昂贵计算或数据库查询,而是从内存或缓存存储中快速提供缓存的响应。缓存响应可减少响应时间并提高 API 的整体性能。
- 节省带宽:通过获取缓存的响应,后续请求无需每次都传输完整的响应内容,进而有效节省了带宽资源。缓存响应可减少通过网络发送的数据量。
- 减少服务器负载:通过提供缓存的响应,您的服务器可以处理更少的请求,从而减少服务器负载并提高可扩展性。这在处理高流量或资源密集型 API 时尤其有用。
.NET 实现
要在 .NET 6 Web API 中启用响应缓存,可以使用内置的ResponseCaching 中间件和[ResponseCache]属性。
添加依赖:
services.AddResponseCaching()
Add Middleware:
app.UseResponseCaching();
在控制器中使用:
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
[HttpGet]
[ResponseCache(Duration = 60, VaryByQueryKeys = new[] { "category" })]
public IActionResult GetProducts(string category)
{
// Implementation to retrieve and return products
}
}
在此示例中,ResponseCache
属性被应用于ProductsController
中的GetProducts
操作。其中,Duration
属性设定了缓存的持续时间(单位为秒),本例中设置为60秒。VaryByQueryKeys属性指示应针对“category”查询参数的不同值单独缓存响应。
用户输入验证
什么是用户输入验证?
用户输入验证是在 API 中接受和处理用户输入的数据之前检查和验证该数据的过程。它涉及验证输入的格式、类型和完整性,以防止常见的安全漏洞。您可以保护您的应用程序免受 SQL 注入、XSS(跨站脚本)或命令注入攻击等漏洞的影响。
为什么要使用用户输入验证?
您可能应该使用用户输入验证来确保数据完整性和准确性,通过防止潜在漏洞来增强应用程序的安全性,通过提供及时反馈和防止错误来改善用户体验,并最终创建可靠、安全且用户友好的应用程序。
您应当知晓的三大缘由(其中第三个是我最为赞成的):
- 数据完整性:通过验证用户输入,您可以强制执行业务规则、数据约束和特定格式要求。这有助于保持数据的完整性和一致性。
- 安全漏洞预防:用户输入验证通过检测和拒绝恶意或格式错误的输入,帮助保护您的 API 免受常见安全风险。它确保您的 API 处理的数据是值得信赖且可以安全处理的。
- 错误处理:验证用户输入允许您在检测到无效输入时提供有意义的错误消息和响应。这有助于用户理解并纠正他们的输入,从而带来更好的用户体验。
.NET Web API 示例
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
[HttpPost]
public IActionResult CreateProduct([FromBody] ProductDto product)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Implementation to create a new product
}
}
// ProductDto.cs
public class ProductDto
{
[Required]
public string Name { get; set; }
[Range(0, 100)]
public int Quantity { get; set; }
// Other properties and validation attributes
}
异常处理
什么是异常处理?
异常可能因各种原因而出现,例如编程错误、无效输入或外部依赖性。正确的异常处理机制使您能够妥善处理错误、从故障中恢复,并向客户端提供恰当的响应。这一过程涉及管理和响应API代码执行期间所出现的各种意外情况。
为什么要使用异常处理?
首先,异常处理允许正确的错误管理和优雅地处理程序执行期间可能出现的意外情况。通过捕获和处理异常,您可以防止应用程序崩溃并向用户提供有意义的错误消息或记录它们以进行故障排除。
其次,异常处理有助于将正常程序流与错误处理逻辑分开,使代码更有组织性、可读性和可维护性。它还能通过将错误处理的逻辑封装在可复用的异常处理模块中,来提升代码的复用性。
总结为3个原因:
- 防止未处理的异常:您可以在异常传播至调用堆栈的更高层级,并可能引发未处理异常、进而导致不可预测行为或系统崩溃之前,及时捕获并妥善处理这些异常。
- “优雅”的错误处理:它有助于向客户端提供有意义的错误响应,改善用户体验。
- 调试和日志记录:正确记录的异常可以提供有关错误原因的宝贵见解并有助于排除故障。
如何在.NET 6中实现全局异常处理中间件?
本例中,全局异常处理中间件添加到Program.cs文件中。它将未处理的异常重定向到ErrorController的HandleError操作,您可以在其中记录错误并向客户端返回标准化错误响应。
中间件:
[ApiController]
[Route("/error")]
[ApiExplorerSettings(IgnoreApi = true)]
public class ErrorController : ControllerBase
{
[Route("{statusCode}")]
public IActionResult HandleError(int statusCode)
{
// Log the error and provide a meaningful error response
var errorResponse = new ErrorResponse
{
StatusCode = statusCode,
Message = "An error occurred."
};
return StatusCode(statusCode, errorResponse);
}
[Route("")]
public IActionResult HandleError()
{
// Log the error and provide a meaningful error response
var errorResponse = new ErrorResponse
{
StatusCode = 500,
Message = "An error occurred."
};
return StatusCode(500, errorResponse);
}
}
记录您的 API
“记录 API”是什么意思?
“记录 API”是指创建描述应用程序编程接口 (API) 的功能、用法和规范的全面且信息丰富的文档的过程。当您创建 API 时,就会有人使用该 API。使用API的人员应当对所采用的端点、请求及响应有直观清晰的认识。出色的文档能够帮助开发人员轻松上手您的API,缩短集成时间,并提升开发人员的满意度。
为什么要记录 API?
为开发人员提供明确的说明和指导,是您应当记录API的主要原因之一。
我还可以再为您提供两个理由:
- 第三方集成:当您希望其他开发人员或组织将他们的应用程序或服务与您的 API 集成时,文档至关重要。它是理解集成要求、数据格式和身份验证机制的基础。
- 提高可用性:记录齐全的 API 提供了有关如何发出请求、处理响应和利用可用功能的清晰说明和示例。这可以更有效地使用 API,并减少出现错误或误解的机会。
使用 Swagger 在 .NET 6 中记录您的 API
有一些工具和库可以帮助您记录 API。最后,虽然您可以选择自己来做(但如果您时间不够充裕,我并不推荐这种方式)。
Swagger 是一个广泛用于 ASP.NET Web API 项目的库。 VIdeces 几乎存在于您遇到的每个 API 项目中。
配置 Swagger 非常简单。
将 Swagger 添加到依赖注入中:
builder.Services.AddSwaggerGen(c =>{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
});
Add Middleware for Swagger and for Swagger UI to display and interact with generated documentation:
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API v1");
});
API 文档编写变得简单
Treblle 实时自动生成 API 的功能可以选择将其打开 Swagger,因为 Treblle 是Open APISpec Initiative的一部分。
结论
总之,本指南旨在向您介绍使用 .NET 6 开发 Web API 项目的最佳实践。通过遵循这些实践,您可以打造出既安全又可扩展、易于维护的API,从而充分满足用户和客户的需求。尽管这些实践是特别针对.NET 6设计的,但其中的许多原则同样适用于其他框架,能够为任何API开发工作提供宝贵的指导和借鉴。
原文链接:https://blog.treblle.com/mastering-net-web-api-best-practices-for-building-powerful-apis/