【问题标题】:Nancy perform AfterRequest action after OnErrorNancy 在 OnError 之后执行 AfterRequest 操作
【发布时间】:2014-04-03 11:11:24
【问题描述】:

我想在对 Nancy 模块的请求的响应标头中添加一些请求时间。我在 RequestStartup 中添加了一些之前/之后的请求处理程序,并且添加了标题没有问题(下面的示例),一切都很好。我还在 ApplicationStartup 中添加了一个 OnError 处理程序,以捕获错误并返回格式良好的 Json 响应。

pipelines.BeforeRequest += ctx =>
    {
        ctx.Items.Add("X-RequestStart", DateTime.Now.ToString());
        return null;
    };

pipelines.AfterRequest += ctx =>
    {
        var now = DateTime.Now;
        try
        {
            //Not got around to forcing the culture on the datetime parsing yet...
            var startTime = DateTime.Parse(ctx.Items["X-RequestStart"].ToString());

            ctx.Response.Headers.Add("X-RequestStart", startTime.ToString(CultureInfo.InvariantCulture));
            ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
            ctx.Response.Headers.Add("X-RequestDuration", (now - startTime).ToString());
        }
        catch (Exception)
        {
            ctx.Response.Headers.Add("X-RequestComplete", now.ToString(CultureInfo.InvariantCulture));
        }
    };

pipelines.OnError += (ctx, exception) =>
    {
        return ErrorResponse.FromException(exception);
    };

然而,我注意到的是,当我抛出错误时,不会执行 AfterRequest 操作 - 因此我在错误响应中没有计时标头。我已经尝试将之前/之后的请求处理移动到应用程序启动,但这也没有效果。

问题实际上分为两部分,首先,是否有可能让框架在执行 OnError 操作后执行 AfterRequest 操作,或者是否设置管道以防止这种情况发生,其次,是否应该这些之前/之后的请求操作是 RequestStartup 或 ApplicationStartup 的一部分吗? ApplicationStartup 似乎对错误处理很明智,而 RequestStartup 似乎对与响应标头进行交互很明智,因为它应该基于每个请求,但我不确定是否有这样的约定,或者我的假设是否不正确。

【问题讨论】:

  • 我注意到错误的类似行为。我所看到的是上下文的响应属性为空。这可能会导致您的 AfterRequest 无法运行。只是一个提示。
  • 有趣。我没有检查过。当 OnError 触发时,我正在生成响应,但响应是在 OnError 委托中设置的,所以我猜这不会回到上下文中。
  • 似乎上下文的响应属性为空 - 但是在 OnError 中将响应添加回上下文似乎没有任何区别 - 我认为这是因为 AfterRequest 挂钩已经通过这点。这是我通过在 OnError 中放置操作来严重处理错误的情况,还是有办法解决这个问题来保持/添加对上下文的响应?
  • 你找到答案了吗?
  • 不,我没有找到解决方案 - 很高兴拥有最终不需要的解决方案。

标签: nancy


【解决方案1】:

不幸的是,这在 NancyFx 中似乎是不可能的。我详细查看了源代码,特别是DefaultRequestDispatcherDispatch 捕获路由处理过程中抛出的任何异常,调用ResolveErrorResult,然后从协商器获取响应。似乎没有可扩展点来修改以这种方式生成的响应。

在我看来,这是开发人员应该考虑解决的疏忽问题。

public async Task<Response> Dispatch(NancyContext context, CancellationToken cancellationToken)
{
    // TODO - May need to make this run off context rather than response .. seems a bit icky currently
    var resolveResult = this.Resolve(context);

    context.Parameters = resolveResult.Parameters;
    context.ResolvedRoute = resolveResult.Route;

    try
    {
        context.Response = await ExecuteRoutePreReq(context, cancellationToken, resolveResult.Before)
            .ConfigureAwait(false);

        if(context.Response == null)
        {
            context.Response = await this.routeInvoker.Invoke(resolveResult.Route, cancellationToken,
                resolveResult.Parameters, context)
                .ConfigureAwait(false);

            if (context.Request.Method.Equals("HEAD", StringComparison.OrdinalIgnoreCase))
            {
                context.Response = new HeadResponse(context.Response);
            }
        }

        await this.ExecutePost(context, cancellationToken, resolveResult.After, resolveResult.OnError)
            .ConfigureAwait(false);
    }
    catch(Exception ex)
    {
        context.Response = this.ResolveErrorResult(context, resolveResult.OnError, ex);

        if (context.Response == null)
        {
            throw;
        }
    }

    return context.Response;
}

private Response ResolveErrorResult(NancyContext context, Func<NancyContext, Exception, dynamic> resolveResultOnError, Exception exception)
{
    if (resolveResultOnError != null)
    {
        var flattenedException = exception.FlattenInnerExceptions();

        var result = resolveResultOnError.Invoke(context, flattenedException);
        if (result != null)
        {
            return this.negotiator.NegotiateResponse(result, context);
        }
    }

    return null;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-09-04
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-14
    • 2016-07-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多