介绍
大家都知道性能是API的流行语。而相应时间则是API性能的一个重要并且可测量的参数。在本文中,我们将了解如何使用代码来测量API的响应时间,然后将响应时间数据返回到客户端。
作者:依乐祝
原文地址:https://www.cnblogs.com/yilezhu/p/9520808.html
我们为什么需要测量响应时间
首先,让我们先花一点时间思考下为什么我们需要这么一个特性来测量API的响应时间。下面是编写代码来捕获响应时间的一些场景。
- 您需要为您的客户定义API的SLA(服务水平协议)。客户需要了解API响应的时间。响应时间数据可以帮助我们确定API的SLA。
- 管理层对报告应用程序的速度快慢感兴趣。您需要有数据来证实您的报告的声明。报告应用程序的性能并与利益相关者进行分享时值得的。
- 客户端需要具有API的响应时间的信息,以便它们可以跟踪在客户端和服务器上花费了多少时间。
您可能在项目中也遇到过类似的请求,因此研究一种捕获API响应时间的方法是值得的。
在哪里添加测量代码?
让我们探索一些方法来捕获API的响应时间,主要集中在捕获API中花费的时间。我们的目标是计算从Asp.net Core运行时接收请求到处理响应并从服务器返回结果所经过的时间(以毫秒为单位)。
我们需要忽略哪些因素?
重要的是要理解这个讨论不包括花在N/W上的时间,以及在IIS和应用程序池启动中花费的时间。如果应用程序池未启动并运行,则第一个请求可能会影响API的总体响应时间。我们可以使用一个应用程序初始化模块,但这超出了本文的范围。
第一次尝试
捕获API响应时间的一种非常异想天开的方法是在开始和结束时向每个API方法添加如下代码,然后测量增量以计算响应时间,如下所示。
// GET api/values/5
[HttpGet]
public IActionResult Get() {
// Start the watch
var watch = new Stopwatch();
watch.Start();
// Your actual Business logic
// End the watch
watch.Stop();
var responseTimeForCompleteRequest = watch.ElapsedMilliseconds;
}
此代码应该能够计算操作所花费的时间。但由于以下原因,这似乎不是正确的方法。
- 如果API有很多操作,那么我们需要将这个代码添加到多个不利于可维护性的地方。
- 此代码仅测量在方法中花费的时间,它不测量在中间件,过滤器,控制器选择,Action选择,模型绑定等其他活动上花费的时间。
第二次尝试
让我们尝试通过将代码集中在一个地方来改进上面的代码,以便更容易维护。我们需要在执行方法之前和之后执行响应时间的计算代码。如果您使用过早期版本的Asp.net Web API,那么您将熟悉Filter的概念。过滤器允许您在请求处理管道中的特定阶段之前或之后运行代码。
我们将实现一个用于计算响应时间的过滤器,如下所示。我们将创建一个Filter并使用OnActionExecuting启动计时器,然后在方法OnActionExecuted中停止计时器,从而计算API的响应时间。
public class ResponseTimeActionFilter: IActionFilter {
private const string ResponseTimeKey = "ResponseTimeKey";
public void OnActionExecuting(ActionExecutingContext context) {
// Start the timer
context.HttpContext.Items[ResponseTimeKey] = Stopwatch.StartNew();
}
public void OnActionExecuted(ActionExecutedContext context) {
Stopwatch stopwatch = (Stopwatch) context.HttpContext.Items[ResponseTimeKey];
// Calculate the time elapsed
var timeElapsed = stopwatch.Elapsed;
}
}
此代码不是计算响应时间的可靠技术,因为它没有解决计算执行中间件,控制器选择,操作方法选择,模型绑定等所花费的时间的问题。过滤器管道在MVC选择Action后执行。因此,它实际上无法检测在其他Asp.net管道中花费的时间。
第三次尝试
我们将使用Asp.net Core中间件来计算API的响应时间
所以,什么是中间件呢?
基本上,中间件是处理请求/响应的软件组件。中间件被组装到应用程序管道中并在传入请求中提供服务。每个组件执行以下操作。
选择是否将请求传递给管道中的下一个组件。
可以在调用管道中的下一个组件之前和之后执行工作。
如果您在ASP.NET中使用过HTTPModules或HTTPHandler,那么您可以将中间件视为ASP.NET Core中的替代品。一些中间件的例子是 :
MVC中间件
Authentication中间件
Static File Serving
Caching
-
CORS 等等
我们希望在请求进入ASP.NET Core管道后添加代码以启动计时器,并在管道处理响应后停止计时器。请求管道开始时的自定义中间件似乎是访问请求最早访问并在管道中执行最后一步之前进行访问的最佳方法。
我们将构建一个响应时间中间件,我们将其作为第一个中间件添加到请求管道中,以便我们可以在请求进入Asp.net Core管道后立即启动计时器。
如何处理响应时间数据呢?
一旦我们捕获到响应时间数据,我们就可以通过以下方式来进行数据的处理。
- 将响应时间数据添加到报告数据库或分析解决方案。
- 将响应时间数据写入日志文件。
- 将响应时间数据传递到消息队列,该消息队列可以由另一个应用程序进一步处理以进行报告和分析。
- 使用响应头将响应时间信息发送到使用我们的Rest API的客户端应用程序。
可能还有其他有用的方法来使用响应时间数据。您可以在评论区进行留言,并告诉我您是如何处理应用程序中的响应时间数据的。
我们开始写代码吧
我们将按照下面的处理步骤来进行代码的编写。
- 计算API的响应时间数据
- 通过在响应头中传递数据将数据报告回客户端应用程序。
ResponseTimeMiddleware的完整代码片段如下所示:
public class ResponseTimeMiddleware {
// Name of the Response Header, Custom Headers starts with "X-"
private const string RESPONSE_HEADER_RESPONSE_TIME = "X-Response-Time-ms";
// Handle to the next Middleware in the pipeline
private readonly RequestDelegate _next;
public ResponseTimeMiddleware(RequestDelegate next) {
_next = next;
}
public Task InvokeAsync(HttpContext context) {
// Start the Timer using Stopwatch
var watch = new Stopwatch();
watch.Start();
context.Response.OnStarting(() => {
// Stop the timer information and calculate the time
watch.Stop();
var responseTimeForCompleteRequest = watch.ElapsedMilliseconds;
// Add the Response time information in the Response headers.
context.Response.Headers[RESPONSE_HEADER_RESPONSE_TIME] = responseTimeForCompleteRequest.ToString();
return Task.CompletedTask;
});
// Call the next delegate/middleware in the pipeline
return this._next(context);
}
}
代码说明
主要的代码是在InvokeAsync方法中,一旦请求进入到第一个中间件,我们使用秒表类来启动秒表,然后在处理请求完成后并且响应准备好返回给客户端的Response后停止秒表。OnStarting方法提供了编写自定义代码的机会,以便在将响应头发送到客户端之前添加要调用的委托中。
最后,我们在自定义标题中添加响应时间信息。我们使用X-Response-Time-ms标头作为响应标头。作为惯例,自定义标题以X开头。
总结
在本文中,我们了解了如何利用ASP.NET中间件来管理跨领域问题,例如测量API的响应时间。使用中间件还有其他各种有用的用例,可以帮助重用代码并提高应用程序的可维护性。
本文翻译自https://www.c-sharpcorner.com/technologies/Asp-Net-core
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=36oxtdlslwowo