Asp.Net Core 7中Kestrel抛出BadHttpRequestException异常求助
Asp.Net Core 7快速点击按钮发起Ajax请求时后端异常问题
场景说明
前端用户每秒点击按钮发起Ajax请求,后端控制器处理请求时抛出Unexpected end of request content异常。
后端控制器代码
[ApiController] [Route("api")] public class FrontWcController : ControllerBase { [HttpPost("change")] public IActionResult GetFromFrontSendToErp(ParametrsForButton requestData) { string wcGuid = requestData.WcGuid; string operation = requestData.Operation; string skusSerial = requestData.SkusSerial; string boxSerial = requestData.BoxSerial; int actionNumber = requestData.ActionNumber; int operationNumber = requestData.OperationNumber; int checkBox = requestData.CheckBox; string actionHumanString = "Undefined"; switch (actionNumber) { case 1: actionHumanString = "Started"; break; case 2: actionHumanString = "Pause"; break; case 3: actionHumanString = "Finished"; break; case 4: actionHumanString = "Exeption"; break; case 5: actionHumanString = "Started"; break; default: Console.WriteLine("Cant change status. Set to default"); break; } DateTime dateTimeOfOperation = DateTime.UtcNow; MainIncomingChangesSaverList.IncomingChangesSaversList.Enqueue(new IncomingChangesSaver() { WcGuid = wcGuid, Operation = operation, SkusSerial = skusSerial, BoxSerial = boxSerial, ActionNumber = actionNumber, OperationNumber = operationNumber, CheckBox = checkBox, ActionHumanString = actionHumanString, DateTimeOfChange = dateTimeOfOperation }); using (ApplicationContext db = new ApplicationContext()) { if (actionNumber == 2 || actionNumber == 5) { Pause pause = new Pause(){wcGuid = wcGuid, Operation = operation, BoxSerial = boxSerial, SkusSerial = skusSerial, ActionNumber = actionNumber, DateTime = dateTimeOfOperation}; db.Pauses.Add(pause); } Change change = new Change() { wcGuid = wcGuid, Operation = operation, BoxSerial = boxSerial, SkusSerial = skusSerial, ActionNumber = actionNumber, DateTime = dateTimeOfOperation }; db.Changes.Add(change); db.SaveChanges(); } return Ok("Request successfuly completed"); } }
抛出的异常信息
fail: Microsoft.AspNetCore.Server.Kestrel[13] Connection id "0HMU4QP2AD7CS", Request id "0HMU4QP2AD7CS:00000001": An unhandled exception was thrown by the application. Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Unexpected end of request content. at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1ContentLengthMessageBody.ReadAsyncInternal(CancellationToken cancellationToken) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.ReadAsyncInternal(Memory`1 destination, CancellationToken cancellationToken) at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token) at System.Text.Json.Serialization.ReadBufferState.ReadFromStreamAsync(Stream utf8Json, CancellationToken cancellationToken, Boolean fillBuffer) at System.Text.Json.JsonSerializer.ReadFromStreamAsync[TValue](Stream utf8Json, JsonTypeInfo jsonTypeInfo, CancellationToken cancellationToken) at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding) at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonInputFormatter.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.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) 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 Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
解决方案
1. 前端添加防抖逻辑
快速点击会导致前一个请求被中断,引发请求内容截断。给按钮设置300-500ms的冷却时间,避免短时间内重复发起请求:
let debounceTimer = null; document.getElementById('yourButton').addEventListener('click', () => { if (debounceTimer) clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { // 发起Ajax请求 fetch('/api/change', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(yourRequestData) }); }, 300); // 300ms冷却时间,可根据需求调整 });
2. 后端全局捕获该异常
在Program.cs中配置全局异常处理,捕获BadHttpRequestException并返回友好响应,避免程序崩溃:
app.UseExceptionHandler(errorApp => { errorApp.Run(async context => { context.Response.StatusCode = StatusCodes.Status400BadRequest; context.Response.ContentType = "application/json"; var exceptionFeature = context.Features.Get<IExceptionHandlerPathFeature>(); if (exceptionFeature?.Error is BadHttpRequestException) { await context.Response.WriteAsJsonAsync(new { Message = "请求内容不完整,请稍后重试" }); } }); });
3. 前端控制请求并发状态
用标志位判断当前是否有请求在进行,确保上一个请求完成后再发起下一次请求:
let isRequestInProgress = false; document.getElementById('yourButton').addEventListener('click', async () => { if (isRequestInProgress) return; isRequestInProgress = true; try { const response = await fetch('/api/change', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(yourRequestData) }); // 处理响应 } catch (error) { // 处理错误 } finally { isRequestInProgress = false; } });
4. 验证请求实体类匹配性
确认ParametrsForButton类的属性与前端发送的JSON字段完全一致,避免序列化过程中出现异常:
public class ParametrsForButton { public string WcGuid { get; set; } public string Operation { get; set; } public string SkusSerial { get; set; } public string BoxSerial { get; set; } public int ActionNumber { get; set; } public int OperationNumber { get; set; } public int CheckBox { get; set; } }
内容的提问来源于stack exchange,提问作者Alexey Burakov
相关产品推荐
相关产品推荐

