• 关于.Net Core下因客户端主动取消导致Request请求[FromBody]模型绑定读取异常BadHttpRequestException


      最近我们的接口老是会出现BadHttpRequestException异常,但是手动查看报错的页面却一点问题没有,很奇怪,后来仔细研究这个异常。异常原因其实根据异常对象本身就已经能分析出来了(由于第一次遇到不清楚怎么造成的,尴尬),就是由于无法正常读取Http-Request请求对象里的内容导致的异常!但是什么情况下会导致这个情况,不得而知。  后来百度其他朋友的文章,终于了解到发生当前错误的原因:

      是由于当请求出现并发,而请求的线程池又不够使用,前面的请求阻塞后面的请求时,后面的请求强制取消后就会导致后面的请求在被接收程序处理Request内容时发生异常,即:BadHttpRequestException

    先看下接口是怎么接收的:

    [HttpPost]
    public async Task<IActionResult> PPIFrameInit([FromBody] PaypalClientRequest parames)
    {
          //...  
    }

    很显然,接口采用的是自动绑定Model模型Request-Body的方式,那么如果按照上述请求就很容易发生下面的异常了。

    异常内容如下:

    ClientIP:157.185.158.160 
    URL:http://www.coowigsby.com/ajax/paydd/PPIFrameInit 
    Type:Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException 
    Msg:Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Unexpected end of request content.
       at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelBadHttpRequestException.Throw(RequestRejectionReason reason)
       at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1ContentLengthMessageBody.ReadAsyncInternal(CancellationToken cancellationToken)
       at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.ReadAsyncInternal(Memory`1 destination, CancellationToken cancellationToken)
       at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
       at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.DrainAsync(Stream stream, ArrayPool`1 bytePool, Nullable`1 limit, CancellationToken cancellationToken)
       at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
       at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
       at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value, Object container)
       at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
    --- End of stack trace from previous location ---
       at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
    --- End of stack trace from previous location ---
       at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
       at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
       at MeShop.CacheResponse.CacheResponseMiddleware.Invoke(HttpContext httpContext) in /builds/sitegroup/meshop/meshop/MeShop.CacheResponse/CacheResponseMiddleware.cs:line 56
       at MeShop.View.Shop.Models.CheckExpirationMiddleware.Invoke(HttpContext httpContext) in /builds/sitegroup/meshop/meshop/MeShop.View.Shop/Models/CheckExpirationMiddleware.cs:line 38
       at MeShop.WebCommon.Cache.ResponseDistributedCacheMiddleware.Invoke(HttpContext httpContext) in /builds/sitegroup/meshop/meshop/MeShop.WebCommon/Cache/ResponseDistributedCacheMiddleware.cs:line 105
       at Microsoft.AspNetCore.ResponseCaching.ResponseCachingMiddleware.Invoke(HttpContext httpContext)
       at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
       at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
       at MeShop.WebCommon.CircuitBreakerWebMiddleware.<>c__DisplayClass13_0.<<InvokeAsync>b__1>d.MoveNext() in /builds/sitegroup/meshop/meshop/MeShop.WebCommon/Middleware/CircuitBreakerWebMiddleware.cs:line 246
    --- End of stack trace from previous location ---
       at Polly.AsyncPolicy.<>c__DisplayClass40_0.<<ImplementationAsync>b__0>d.MoveNext()
    --- End of stack trace from previous location ---
       at Polly.CircuitBreaker.AsyncCircuitBreakerPolicy.<>c__DisplayClass8_0`1.<<ImplementationAsync>b__0>d.MoveNext()
    --- End of stack trace from previous location ---
       at Polly.CircuitBreaker.AsyncCircuitBreakerEngine.ImplementationAsync[TResult](Func`3 action, Context context, CancellationToken cancellationToken, Boolean continueOnCapturedContext, ExceptionPredicates shouldHandleExceptionPredicates, ResultPredicates`1 shouldHandleResultPredicates, ICircuitController`1 breakerController)
       at Polly.CircuitBreaker.AsyncCircuitBreakerPolicy.ImplementationAsync[TResult](Func`3 action, Context context, CancellationToken cancellationToken, Boolean continueOnCapturedContext)
       at Polly.AsyncPolicy.ExecuteAsync(Func`3 action, Context context, CancellationToken cancellationToken, Boolean continueOnCapturedContext)
       at MeShop.WebCommon.CircuitBreakerWebMiddleware.InvokeAsync(HttpContext context) in /builds/sitegroup/meshop/meshop/MeShop.WebCommon/Middleware/CircuitBreakerWebMiddleware.cs:line 275

    这里列举一下本地调试的复现步骤(本地调试是单线程):

    • 在请求处理过程的某处设置断点
    • 在PostMan或浏览器上先发送A请求,命中断点,不继续往下处理,让请求阻塞
    • 继续发放B请求,这时请求阻塞中,然后点击取消请求
    • 释放断点继续处理,结果是A请求正常处理结束,B请求处理时抛出异常

    解决方法有三种(参考的博客里只介绍了一种):

    • 1_可选择在全局异常过滤器中不处理该异常,不打印错误日志(有掩耳盗铃的嫌疑,不推荐);
    • 2_可以将接口[FromBody]由自动绑定改成代码读取接收,使用try-catch捕获异常单独处理(跟1类似,也不推荐);
    • 3_可以增加最小线程池数量,使其能够拥有足够的线程处理并发请求(确实访问量太大,可以使用);
    • 4_优化现有的代码:分析当时的请求为何造成了线程不够用的原因,把耗时较长造成阻塞的有问题的方法处理掉,更新后再继续观察(适用于访问量没有那么大,部分接口代码质量不好的情况时使用);

    参考博客:关于.Net Core3.0下因客户端主动取消请求导致的Request.Body异常

  • 相关阅读:
    NSIS附加数据库,分离数据库脚本代码
    C# 昨天今天明天上周本周下周上月本月下月等日期计算
    NSIS安装MSDE2000和NET2.0脚本代码
    sql 获取指定数据表的所有字段名称的字符串
    如何检测TerraGate的InternetLicense运行是否正常
    Skyline TEP5.1.3二次开发入门——初级(七)
    Skyline软件二次开发初级——2如何在WEB页面中控制三维地图的观察点坐标和角度
    如何实现Skyline与微软bing地图的联动
    Skyline软件二次开发初级——3如何在WEB页面中的三维地图上创建几何对象
    Skyline软件二次开发初级——1如何在web页面中添加控件和加载三维地图数据
  • 原文地址:https://www.cnblogs.com/lxhbky/p/16033691.html
Copyright © 2020-2023  润新知