目录:
先决条件:介绍本文旨在全面概述程序员在创建 API 时应遵循的最佳实践。无论是使用 .NET 6 Web API 还是任何其他框架,这些做法对于提供设计良好且可靠的 API 都是必不可少的。
对 API 进行版本控制
什么是 API 版本控制?
API 是软件。软件的每个部分都需要在某个时候进行更新。在 API 上创建一些更新时,需要确保这些更改不会影响 API 使用者(用户)。为确保这一点,您需要引入 API 版本控制。
为什么需要 API 版本控制?
如果您的目标是开发强大且可扩展的 Web 应用程序,请考虑从 Toptal 聘请 ASP.NET 开发人员。凭借他们在创建高性能解决方案方面的深厚专业知识,Toptal 的 ASP.NET 专业人员有能力提供满足复杂业务需求的尖端应用程序,确保顶级公司和初创公司有效地实现其技术目标。
向后兼容性:它确保客户端可以继续使用旧版本,而新客户端可以利用更新的功能。
API 演进:随着 API 的演进,版本控制允许您引入新功能、弃用过时的功能并进行改进,而不会中断现有客户端。
客户端灵活性:不同的客户端可能有不同的要求,或者可能需要特定版本的 API 中提供的特定功能。
ASP.NET Web API 版本控制
GET /products HTTP/1.1
Host: api.example.com
Accept: application/json
X-API-Version: 2
Microsoft.AspNetCore.Mvc.Versioning
//Program.cs C# class:
builder.Services.AddApiVersioning(options =>
{
options.ReportApiVersions = true;
options.DefaultApiVersion = new ApiVersion(1, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ApiVersionReader = new UrlSegmentApiVersionReader();
});
在 ProductsController 中,使用 MapToApiVersion 属性修饰操作方法,以指定每个方法的版本。
[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 开发变得轻而易举!:D
使用正确的 HTTP 方法
什么是 HTTP 方法?
最常用的方法是:
GET:检索资源的表示形式。POST:创建新资源。
PUT:更新现有资源或创建新资源(如果不存在)。
PATCH:部分更新现有资源。
DELETE:删除资源。
使用正确的 HTTP 方法很重要,因为它可以确保遵守 REST 架构风格的原则,改进 API 设计和可维护性,通过实施适当的访问控制来增强安全性,促进可伸缩性和缓存机制,并实现与 Web 上各种客户端和服务器的互操作性和兼容性。
RESTful 原则:正确使用 HTTP 方法符合具象状态传输 (REST) 的原则。RESTful API 利用这些方法的语义为客户端创建统一且可预测的接口。
**语义清晰:**每个 HTTP 方法都具有特定的含义,使您的 API 端点更加直观和不言自明。开发人员可以根据所使用的 HTTP 方法轻松了解端点的用途和功能。
何时使用每种 HTTP 方法?
GET:使用 GET 从资源中检索数据。它应该不会对服务器产生任何副作用。POST:使用 POST 创建新资源。请求有效负载通常包含新资源的数据,服务器为其分配唯一标识符。
PUT:使用 PUT 更新现有资源或创建新资源(如果不存在)。请求负载包含要更新的资源的完整表示形式。
PATCH:使用 PATCH 对现有资源执行部分更新。请求有效负载仅包括需要应用于资源的更改。
DELETE:使用 DELETE 删除由其唯一标识符标识的资源。
故事时间:
好像这还不够,当我无意中设置“PUT”方法而不是“DELETE”来删除资源时,我遇到了另一个错误,导致数据持久且顽固。
.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
}
}
保护 API
开发 .NET 6 Web API 时,API 安全性需要考虑几个重要方面:
认证:
.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"))
};
});
}
授权
// 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
}
}
速率限制
在 .NET 6 中,可以使用 AspNetCoreRateLimit 库实现此目的。
services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
app.UseIpRateLimiting();
{
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIpHeader": "X-Forwarded-For",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*",
"Period": "1s",
"Limit": 5
}
]
}
}
缓存响应
什么是响应缓存?
为什么要使用响应缓存?
我将根据我的经验向您解释 3 个最有力的原颍�
改进的性能:无需重复执行相同的昂贵计算或数据库查询,而是从内存或缓存存储中快速提供缓存响应。缓存响应可缩短响应时间并提高 API 的整体性能。节省带宽:后续请求可以获取缓存的响应,从而节省带宽,而不是每次都传输整个响应。缓存响应可减少通过网络发送的数据量。
减少服务器负载:通过提供缓存响应,服务器处理的请求更少,从而减少服务器负载并提高可伸缩性。这在处理高流量或资源密集型 API 时尤其有用。
.NET 实现
添加依赖项:
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
}
}
Duration 属性指定缓存持续时间(以秒为单位)(在本例中为 60 秒),而 VaryByQueryKeys 属性指示应针对“category”查询参数的不同值单独缓存响应。
用户输入验证
什么是用户输入验证?
为什么要使用用户输入验证?
您应该了解的 3 大理由(第 3 个是我的最爱):
数据完整性:通过验证用户输入,可以强制执行业务规则、数据约束和特定格式要求。这有助于保持数据的完整性和一致性。安全漏洞防护:用户输入验证通过检测和拒绝恶意或格式错误的输入,帮助保护 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
}
异常处理
什么是异常处理?
为什么要使用异常处理?
其次,异常处理有助于将正常程序流与错误处理逻辑分离,使代码更有条理、更可读、更易于维护。它还通过将错误处理逻辑封装在可重用的异常处理块中来促进代码重用。
防止未处理的异常:可以在异常向上传播到调用堆栈并导致未处理的异常之前捕获和处理异常,从而导致不可预知的行为或崩溃。
**“优雅”错误处理:**它有助于向客户提供有意义的错误响应,从而改善用户体验。
调试和日志记录:正确记录的异常提供了对错误原因的宝贵见解,并有助于进行故障排除。
如何在 .NET 6 中实现全局异常处理中间件?
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
“Documenting API”是什么意思?
为什么要记录 API?
我还可以给你两个理由:
第三方集成:当您希望其他开发人员或组织将其应用程序或服务与您的 API 集成时,文档至关重要。它是了解集成要求、数据格式和身份验证机制的基础。改进的可用性:有据可查的 API 提供了有关如何发出请求、处理响应和利用可用功能的清晰说明和示例。这样可以更有效地使用 API,并减少错误或误解的机会。
使用 Swagger 在 .NET 6 中记录 API
Swagger 是一个广泛用于 ASP.NET Web API 项目的库。VIdeces 几乎存在于您遇到的每个 API 项目中。了解更多: https://swagger.io/solutions/api-development/
将 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 文档变得简单
使用 .NET 6 开发 Web API 项目的最佳实践。通过遵循这些做法,您可以确保安全、可扩展且可维护的 API,以满足用户和客户端的需求。虽然这些实践是专门为 .NET 6 量身定制的,但其中许多实践也可以应用于其他框架,从而为任何 API 开发工作提供宝贵的知识。
该文章在 2024/6/19 19:00:56 编辑过