BadHttpRequestException из-за MinRequestBodyDataRate и плохого соединения - PullRequest
0 голосов
/ 18 мая 2018

У меня есть веб-приложение ASP.NET Core, которое принимает закачки файлов от аутентифицированных пользователей, а также обрабатывает некоторые ошибки, чтобы уведомить меня о возникновении исключения ( Exceptional ).Моя проблема в том, что я периодически получаю оповещения BadHttpRequestException с из-за того, что пользователи получают доступ к приложению через мобильные устройства в областях с ненадежным покрытием.Я имел обыкновение получать это также с 2.0, но до тех пор, пока описание исключения не было обновлено в 2.1, я никогда не знал, что это было конкретно связано с MinRequestBodyDataRate, или что это настраиваемо.Я увеличил значения по умолчанию (240 байт за 5 секунд) со следующим

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseKestrel(options =>
            {
                options.Limits.MinRequestBodyDataRate = new MinDataRate(240.0, TimeSpan.FromSeconds(10.0));
            }) 
            .UseStartup<Startup>();

Это удваивает продолжительность ожидания клиента / браузера, но я все еще получаю предупреждения об ошибках.Я не могу контролировать плохой прием пользователей, но я все еще надеюсь попытаться найти способ смягчить ошибки.Я могу продлить минимум еще больше, но я не хочу делать это для всего приложения, если это возможно.В идеале это будет конкретный маршрут / действие, обрабатывающее загрузку.В документации, которую мне удалось найти, указано, что этот минимум можно настроить с помощью IHttpMinRequestBodyDataRateFeature.Я думал о том, чтобы поместить это в действие, но я не думаю, что действие даже вызывается, пока привязка модели не загрузит весь файл, чтобы связать его с моим параметром.

public async Task<IActionResult> Upload(IFormFile file)
{
    var minRequestBodyDataRateFeature = HttpContext.Features.Get<IHttpMinRequestBodyDataRateFeature>();
    minRequestBodyDataRateFeature.MinDataRate = new MinDataRate(240, TimeSpan.FromSeconds(30));
    myDocumentService.SaveFile(file);
}

Это несколькосмягчается тем фактом, что я ранее реализовал загрузку по частям, и сохраняю файл только в службу / базу данных, когда приходит последний фрагмент (создание файла постепенно во временном местоположении между ними).Но я все еще получаю эти BadHttpRequestException с даже при увеличенной продолжительности, сделанной через CreateWebHostBuilder (порция не показана, поскольку это не имеет значения).

Я думаю, что лучшая ставка может быть попытаться иподключите его в методе configure, который устанавливает промежуточное ПО, но я не уверен, что лучше всего применить его только к одному действию.URL может быть?И мне интересно, какие будут последствия, если я полностью отключу минимальную частоту, установив ее на null.

Я просто пытаюсь сделать подключение более терпимым к соединениям низкого качества, не нарушая при этомслишком много изо дня в день для других аспектов приложения.

  1. Мне нужен способ применить изменение (потенциально в промежуточном программном обеспечении Startup.Configure()) таким образом, чтобы оно относилось только кзатронутый маршрут / URL / действие.
  2. Есть ли какие-либо последствия для рассмотрения, если я отключу его полностью (вместо его увеличения) для этого маршрута / URL / действия?Полное приложение?
  3. Если что-то из этого не выйдет, безопасно ли просто игнорировать эти ошибки и никогда не регистрировать их?Создавать ли я мертвую зону для вредоносных взаимодействий с приложением / сервером?

Ответы [ 2 ]

0 голосов
/ 02 мая 2019

Вот вариант, который вы можете сделать, используя ResourceFilter , который выполняется до привязки модели.

using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Features;
using Microsoft.Extensions.DependencyInjection;

namespace YourNameSpace
{
    public class RateFilter : Attribute, IResourceFilter
    {
        private const string EndPoint = "YourEndPoint";

        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            try
            {
                if (!context.HttpContext.Request.Path.Value.Contains(EndPoint))
                {
                    throw new Exception($"This filter is intended to be used only on a specific end point '{EndPoint}' while it's being called from '{context.HttpContext.Request.Path.Value}'");
                }

                var minRequestRateFeature = context.HttpContext.Features.Get<IHttpMinRequestBodyDataRateFeature>();
                var minResponseRateFeature = context.HttpContext.Features.Get<IHttpMinResponseDataRateFeature>();
                //Default Bytes/s = 240, Default TimeOut = 5s

                if (minRequestRateFeature != null)
                {
                    minRequestRateFeature.MinDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
                }

                if (minResponseRateFeature != null)
                {
                    minResponseRateFeature.MinDataRate = new MinDataRate(bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
                }
            }
            catch (Exception ex)
            {
                //Log or Throw
            }
        }

        public void OnResourceExecuted(ResourceExecutedContext context)
        {
        }
    }
}

Затем вы можете использовать атрибут в определенной конечной точке, например

        [RateFilter]
        [HttpPost]
        public IActionResult YourEndPoint(YourModel request)
        {
            return Ok();
        }
  • Вы можете дополнительно настроить фильтр так, чтобы он принимал конечную точку / скорости в качестве параметров ctor.
  • Вы также можете удалить проверку для определенной конечной точки
  • Вы можете return вместо throw
0 голосов
/ 05 июня 2018

Я заметил ту же проблему.У меня есть файлы большего размера, которые пользователи могут загрузить с моего сайта, и некоторые люди, в зависимости от региона, имеют низкую скорость загрузки, и загрузка через некоторое время останавливается.Я также вижу исключения в журнале.

Я не рекомендую отключать эту функцию из-за некоторых зависших или очень медленных соединений, которые могут суммироваться.Просто увеличьте время и понизьте ставку до значения, при котором вы можете сказать, что ваша веб-страница все еще пригодна для использования.

Я бы не стал делать это для определенных URL.Это не повредит, когда страницы имеют одинаковые настройки, если вы не заметите некоторые проблемы с производительностью.

Также имейте в виду, что есть также опция MinResponseDataRate.

Лучший способ - установить некоторые разумные значения при запуске приложения для всех маршрутов.В журнале всегда будут исключения от людей, которые теряют соединение с Интернетом, и kestrel должен через некоторое время закрыть соединение, чтобы освободить ресурсы.

       public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseKestrel(options =>
            {
                options.Limits.MinRequestBodyDataRate =
                    new MinDataRate(bytesPerSecond: 80, gracePeriod: TimeSpan.FromSeconds(20));
                options.Limits.MinResponseDataRate =
                    new MinDataRate(bytesPerSecond: 80, gracePeriod: TimeSpan.FromSeconds(20));
            })
            .ConfigureLogging((hostingContext, logging) =>
            {
                logging.ClearProviders();
                logging.SetMinimumLevel(LogLevel.Trace);
            })
            .UseNLog()
            .UseStartup<Startup>()
            .Build();
}

Пожалуйста, также посмотрите на вашу асинхронную загрузку.метод.Убедитесь, что у вас есть ожидание или вернуть задачу.Я не думаю, что это компилируется таким образом.

...