Web API 通常用来与外部模块进行通信、发送和接收数据,作为后端开发人员,应该把写出高性能的应用作为目标。
下面 4 个技巧是我在编写 Web API 的小技巧。
1 、大量数据使用分页查询
接口传输大量数据可能会导致严重的性能问题、过多的内存消耗和速度减慢。为了缓解这些可能的瓶颈,强烈建议使用分页查询。
分页查询允许请求者选择特定范围的值。
下面是在 ASP. NET Core 中实现分页的方法之一:
[HttpGet("error-logs/{skip}/{take}")]
public async Task<ActionResult<List<Log>>> GetErrorLogsPaginated([FromRoute] int skip = 0, [FromRoute] int take = 10)
{
var logErrors = await _context.Logs
.Where(l => l.LogLevel == InternalLogLevel.Error)
.Skip(skip)
.Take(take)
.OrderBy(c => c.Id)
.ToListAsync();
return Ok(logErrors);
}
2、减少网络往返次数
避免网络往返意味着应该尽可能在单个调用中查询必要数据,而不是进行多个调用,然后将它们放在一起。
[HttpGet("services-ids")]
public async Task<ActionResult<List<int>>> GetServicesIds()
{
var servicesIds = await _context.Services.AsNoTracking().Select(x => x.Id).ToListAsync();
return Ok(servicesIds);
}
[HttpGet("logs-with-service")]
public async Task<ActionResult<List<Log>>> GetLogsByServiceIds([FromQuery] List<int> serviceIds)
{
var logs = await _context.Logs
.AsNoTracking()
.Where(s => serviceIds.Contains(s.Id))
.Select(s => new Log
{
Id = s.Id,
Service = s.Service,
})
.ToListAsync();
return Ok(logs);
}
这里有两个接口,第一个接口返回了所有的服务 id,第二个接口返回包含具有这些 id 的记录的日志。在上面的示例中,需要进行两次调用,这是不建议的。
应该按照以下方式进行:
[HttpGet("logs-with-service")]
public async Task<ActionResult<List<Log>>> GetAllServicesWithLogs()
{
var services = await _context.Services
.AsNoTracking()
.ToListAsync();
var serviceIds = services.Select(s => s.Id).ToList();
var logs = await _context.Logs
.AsNoTracking()
.Where(l => serviceIds.Contains(l.ServiceId))
.ToListAsync();
return Ok(logs);
}
3、使用 Task 等待任务完成
使用 async Task 意味着请求管道可以等到异步方法完成。
ASP. NET Core 希望操作方法返回 Task,以便它可以正确继承到异步请求管道中。如果使用 async void,将会导致异步操作完成之前出现响应。
不要使用:async void
[HttpDelete("/{id}")]
public async void DeleteService([FromRoute] int id)
{
await _context.Services.FirstOrDefaultAsync(s => s.Id == id);
await Response.WriteAsync("Successfully deleted record");
}
应该用: async Task
[HttpDelete("/{id}")]
public async Task DeleteService([FromRoute] int id)
{
await _context.Services.FirstOrDefaultAsync(s => s.Id == id);
await Response.WriteAsync("Successfully deleted record");
}
4、对经常访问的数据使用缓存
缓存很有用,它是一种通过减少数据库资源消耗来显著提高应用程序性能的技术。
在第一次请求中,从数据库中检索数据并写入缓存。在后续的请求中,如果数据存在于缓存中,则会立即返回给请求者,而不需要查询数据库。
缓存最适合数据不经常更改的场景,ASP.NET Core 支持两种主要类型的缓存:内存缓存和分布式缓存。
内存缓存非常简单,通过 IMemoryCache 接口提供。IMemoryCache 表示存储在 Web 服务器内存中的缓存。
下面时一个使用内存缓存的示例:
[HttpGet("log-errors-cache-in-memory")]
public async Task<ActionResult<List<Log>>> GetErrorLogsWithCacheInMemory()
{
const string CacheKey = "logs_with_error";
if (!_memoryCache.TryGetValue(CacheKey, out List<Log>? logErrors))
{
logErrors = await _context.Logs
.Where(l => l.LogLevel == InternalLogLevel.Error)
.ToListAsync();
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(30));
_memoryCache.Set(CacheKey, logErrors, cacheEntryOptions);
}
return Ok(logErrors);
}
实现缓存的另一种方式是使用分布式缓存,它可以在多个服务器之间共享,并且通常作为外部服务部署维护。
ASP. NET Core 通过 IDistributedCache 接口提供分布式缓存处理方法,有 Redis、内存、SQL Server、NCache、Azure CosmosDB 多种实现。
要使用分布式缓存,你需要有一个运行的缓存服务实例。
下面的代码展示了一个使用分布式缓存的终端节点:
[HttpGet("log-errors-cache-distributed")]
public async Task<ActionResult<List<Log>>> GetErrorLogsWithCacheDistributed()
{
const string CacheKey = "logs_with_error";
List<Log>? logErrors = await _memcachedClient.GetValueAsync<List<Log>>(CacheKey);
if (logErrors == null)
{
logErrors = await _context.Logs
.Where(l => l.LogLevel == InternalLogLevel.Error)
.ToListAsync();
await _memcachedClient.SetAsync(CacheKey, logErrors, TimeSpan.FromMinutes(30));
}
return Ok(logErrors);
}
两端代码看起来非常相似,最大的区别在于缓存存储的位置。
标签:Web,ASP,logs,await,缓存,Task,API,async,logErrors From: https://www.cnblogs.com/denglei1024/p/18455608