net core httpclient redirect

Продолжая серию статей о «подводных камнях» не могу обойти стороной System.Net.HttpClient, который очень часто используется на практике, но при этом имеет несколько серьезных проблем, которые могут быть сразу не видны.

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

И по завершении посмотреть список открытых соединений через netstat:

Итого, мы видим, что несмотря на конструкцию using, и даже несмотря на то, что выполнение программы полностью завершилось, соединения с сервером остались «висеть». И висеть они будут столько времени, сколько указано в ключе реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay.

Проблему легко можно увидеть, выполнив следующий код:

Указанный в ссылке ресурс позволяет задержать ответ сервера на указнное время, в данном случае — 5 секунд.

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

то выполнение примера заметно ускорится, так как запросы будут выполняться пачками по 5.

После выполнения этого кода любое взаимодействие с Хабром через один и тот же экземпляр HttpClient будет использовать 5 одновременных соединений, а с сайтом «slowwly» — 3 соединения.

Здесь есть еще интересный нюанс — лимит количества соединений для локальных адресов (localhost) по умолчанию равен int.MaxValue. Просто посмотрите результаты выполнения этого кода, предварительно не устанавливая DefaultConnectionLimit:

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

Представим, что разрабатываемая нами система должна нормально работать без принудительного перезапуска в случае, если сервер, с которым она взаимодействует, перешел на другой IP адрес. Например, в случае переключения на другой датацентр из-за сбоя в текущем. Даже если постоянное соединение будет разорвано из-за сбоя в первом датацентре (что тоже может произойти небыстро), кеш DNS не позволит нашей системе быстро отреагировать на такое изменение. То же самое актуально для обращений к адресу, на котором балансировка нагрузки делается через DNS round-robin.

С такими настройками соединение будет закрываться каждые 60 секунд (ConnectionLeaseTimeout) даже несмотря на то, что по нему периодически идет передача данных. Закрытие и пересоздание будет проиходить таким образом, чтобы не мешать корректному выполнению запросов — если время истекло, а в данный момент запрос еще выполняется, соединение будет закрыто после завершения запроса. При каждом пересоздании соединения соответствующий IP адрес в первую очередь будет браться из кеша, и только если время жизни его разрешения истекло (120 секунд), система пошлет запрос на DNS сервер.

Параметр MaxIdleTime в этом сценарии не будет играть роли, так как соединение не бездействует дольше чем 10 секунд.

Оптимальное соотношение этих параметров сильно зависит от конкретной ситуации и нефункциональных требований:

Во время работы тестовой программы можно в цикле запустить netstat через PowerShell для наблюдения за соединениями, которые она устанавливает.

Источник

Http Client Класс

Определение

Предоставляет класс для отправки HTTP-запросов и получения HTTP-ответов от ресурса, идентифицируемого по универсальному коду ресурса (URI). Provides a class for sending HTTP requests and receiving HTTP responses from a resource identified by a URI.

Примеры

В предыдущем примере кода используется async Task Main() точка входа. The preceding code example uses an async Task Main() entry point. Для этой функции требуется C# 7,1 или более поздней версии. That feature requires C# 7.1 or later.

Комментарии

HttpClientЭкземпляр класса выступает в качестве сеанса для отправки HTTP-запросов. The HttpClient class instance acts as a session to send HTTP requests. HttpClientЭкземпляр — это коллекция параметров, применяемых ко всем запросам, выполняемым этим экземпляром. An HttpClient instance is a collection of settings applied to all requests executed by that instance. Кроме того, каждый HttpClient экземпляр использует собственный пул соединений, изолируя его запросы от запросов, выполняемых другими HttpClient экземплярами. In addition, every HttpClient instance uses its own connection pool, isolating its requests from requests executed by other HttpClient instances.

Производные классы не должны переопределять виртуальные методы класса. Derived classes should not override the virtual methods on the class. Вместо этого используйте перегрузку конструктора, которая принимает HttpMessageHandler на себя настройку обработки до или после запроса. Instead, use a constructor overload that accepts HttpMessageHandler to configure any pre- or post-request processing.

Если приложение, использующее HttpClient и связанные классы в System.Net.Http пространстве имен, планирует загружать большие объемы данных (50 МБ или более), приложение должно выполнять потоковую передачу этих файлов и не использовать буферизацию по умолчанию. If an app using HttpClient and related classes in the System.Net.Http namespace intends to download large amounts of data (50 megabytes or more), then the app should stream those downloads and not use the default buffering. Если используется буферизация по умолчанию, использование памяти клиента будет очень большим, что может привести к значительному снижению производительности. If the default buffering is used the client memory usage will get very large, potentially resulting in substantially reduced performance.

Свойства класса HttpClient не должны изменяться, пока имеются необработанные запросы, так как они не являются потокобезопасными. Properties of HttpClient should not be modified while there are outstanding requests, because it is not thread-safe.

Следующие методы являются потокобезопасными: The following methods are thread safe:

HttpClient предназначен для однократного создания экземпляра и повторного использования в течение всего жизненного цикла приложения. HttpClient is intended to be instantiated once and re-used throughout the life of an application. При создании экземпляра класса HttpClient для каждого запроса будет исчерпано количество сокетов, доступных при высоких нагрузках. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. Это приведет к ошибкам SocketException. This will result in SocketException errors. Ниже приведен пример, использующий HttpClient правильно. Below is an example using HttpClient correctly.

HttpClient— Это интерфейс API высокого уровня, который заключает в оболочку функциональные возможности нижнего уровня, доступные на каждой платформе, где она выполняется. The HttpClient is a high-level API that wraps the lower-level functionality available on each platform where it runs.

На каждой платформе HttpClient пытается использовать оптимальный доступный транспорт: On each platform, HttpClient tries to use the best available transport:

Если это изменение нежелательно, в Windows можно по-прежнему использовать WinHttpHandler ссылку на пакет NuGet и передать его HttpClient конструктору вручную. If this change is undesirable, on Windows you can still use WinHttpHandler by referencing it’s NuGet package and passing it to HttpClient ‘s constructor manually.

Настройка поведения с помощью параметров конфигурации времени выполнения Configure behavior using run-time configuration options

Конструкторы

Инициализирует новый экземпляр класса HttpClient, используя HttpClientHandler, который удаляется при удалении этого экземпляра. Initializes a new instance of the HttpClient class using a HttpClientHandler that is disposed when this instance is disposed.

Инициализирует новый экземпляр класса HttpClient с указанным обработчиком. Initializes a new instance of the HttpClient class with the specified handler. Обработчик удаляется при удалении этого экземпляра. The handler is disposed when this instance is disposed.

Инициализирует новый экземпляр класса HttpClient с предоставленным обработчиком и указывает, должен ли этот обработчик удаляться при удалении этого экземпляра. Initializes a new instance of the HttpClient class with the provided handler, and specifies whether that handler should be disposed when this instance is disposed.

Свойства

Возвращает или задает базовый адрес универсального кода ресурса (URI) интернет-ресурса, используемого при отправке запросов. Gets or sets the base address of Uniform Resource Identifier (URI) of the Internet resource used when sending requests.

Возвращает или устанавливает глобальный прокси-сервер HTTP. Gets or sets the global Http proxy.

Возвращает заголовки, которые должны отправляться с каждым запросом. Gets the headers which should be sent with each request.

Возвращает или задает версию HTTP по умолчанию, используемую в последующих запросах, выполняемых этим экземпляром HttpClient. Gets or sets the default HTTP version used on subsequent requests made by this HttpClient instance.

Возвращает или задает политику выбора версий по умолчанию для неявно созданных запросов в удобных методах, например GetAsync(String) и PostAsync(String, HttpContent). Gets or sets the default version policy for implicitly created requests in convenience methods, for example, GetAsync(String) and PostAsync(String, HttpContent).

Возвращает или задает максимальное число байтов в буфере при чтении содержимого отклика. Gets or sets the maximum number of bytes to buffer when reading the response content.

Возвращает или задает время ожидания для выполнения запроса. Gets or sets the timespan to wait before the request times out.

Методы

Отмена всех ожидающих запросов на этом экземпляре. Cancel all pending requests on this instance.

Отправка запроса DELETE согласно указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a DELETE request to the specified Uri as an asynchronous operation.

Отправка запроса DELETE к указанному URI с токеном отмены в качестве асинхронной операции. Send a DELETE request to the specified Uri with a cancellation token as an asynchronous operation.

Отправка запроса DELETE согласно указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a DELETE request to the specified Uri as an asynchronous operation.

Отправка запроса DELETE к указанному URI с токеном отмены в качестве асинхронной операции. Send a DELETE request to the specified Uri with a cancellation token as an asynchronous operation.

Освобождает неуправляемые ресурсы и удаляет управляемые ресурсы, используемые объектом HttpMessageInvoker. Releases the unmanaged resources and disposes of the managed resources used by the HttpMessageInvoker.

Освобождает неуправляемые ресурсы, используемые объектом HttpClient, и опционально удаляет управляемые ресурсы. Releases the unmanaged resources used by the HttpClient and optionally disposes of the managed resources.

Определяет, равен ли указанный объект текущему объекту. Determines whether the specified object is equal to the current object.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a GET request to the specified Uri as an asynchronous operation.

Отправка запроса DELETE указанному универсальному коду ресурса (URI) с токеном отмены в качестве асинхронной операции. Send a GET request to the specified Uri with a cancellation token as an asynchronous operation.

Отправка запроса GET указанному универсальному коду ресурса (URI) с параметром «выполнение HTTP» в качестве асинхронной операции. Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation.

Отправка запроса GET к указанному универсальному коду ресурса (URI) с параметром «выполнение HTTP» и токеном отмены в качестве асинхронной операции. Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a GET request to the specified Uri as an asynchronous operation.

Отправка запроса DELETE указанному универсальному коду ресурса (URI) с токеном отмены в качестве асинхронной операции. Send a GET request to the specified Uri with a cancellation token as an asynchronous operation.

Отправка запроса GET указанному универсальному коду ресурса (URI) с параметром «выполнение HTTP» в качестве асинхронной операции. Send a GET request to the specified Uri with an HTTP completion option as an asynchronous operation.

Отправка запроса GET к указанному универсальному коду ресурса (URI) с параметром «выполнение HTTP» и токеном отмены в качестве асинхронной операции. Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation.

Отправляет запрос GET согласно указанному универсальному коду ресурса (URI) и возвращает текст ответа в виде массива байтов в асинхронной операции. Sends a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation.

Отправляет запрос GET согласно указанному универсальному коду ресурса (URI) и возвращает текст ответа в виде массива байтов в асинхронной операции. Sends a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде массива байтов в асинхронной операции. Send a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде массива байтов в асинхронной операции. Send a GET request to the specified Uri and return the response body as a byte array in an asynchronous operation.

Служит хэш-функцией по умолчанию. Serves as the default hash function.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде потока в асинхронной операции. Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде потока в асинхронной операции. Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде потока в асинхронной операции. Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде потока в асинхронной операции. Send a GET request to the specified Uri and return the response body as a stream in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде строки в асинхронной операции. Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде строки в асинхронной операции. Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде строки в асинхронной операции. Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation.

Отправка запроса GET согласно указанному универсальному коду ресурса (URI) и возврат текста ответа в виде строки в асинхронной операции. Send a GET request to the specified Uri and return the response body as a string in an asynchronous operation.

Возвращает объект Type для текущего экземпляра. Gets the Type of the current instance.

Создает неполную копию текущего объекта Object. Creates a shallow copy of the current Object.

Асинхронно отправляет запрос PATCH к универсальному коду ресурса (URI), заданному в виде строки. Sends a PATCH request to a Uri designated as a string as an asynchronous operation.

Асинхронно отправляет запрос PATCH с токеном отмены к универсальному коду ресурса (URI), представленному строкой. Sends a PATCH request with a cancellation token to a Uri represented as a string as an asynchronous operation.

Отправляет запрос PATCH в качестве асинхронной операции. Sends a PATCH request as an asynchronous operation.

Отправляет запрос PATCH с токеном отмены в качестве асинхронной операции. Sends a PATCH request with a cancellation token as an asynchronous operation.

Отправка запроса POST по указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a POST request to the specified Uri as an asynchronous operation.

Отправка запроса POST с токеном отмены в качестве асинхронной операции. Send a POST request with a cancellation token as an asynchronous operation.

Отправка запроса POST по указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a POST request to the specified Uri as an asynchronous operation.

Отправка запроса POST с токеном отмены в качестве асинхронной операции. Send a POST request with a cancellation token as an asynchronous operation.

Отправка запроса PUT по указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a PUT request to the specified Uri as an asynchronous operation.

Отправка запроса PUT с токеном отмены в качестве асинхронной операции. Send a PUT request with a cancellation token as an asynchronous operation.

Отправка запроса PUT по указанному универсальному коду ресурса (URI) в качестве асинхронной операции. Send a PUT request to the specified Uri as an asynchronous operation.

Отправка запроса PUT с токеном отмены в качестве асинхронной операции. Send a PUT request with a cancellation token as an asynchronous operation.

Отправляет HTTP-запрос с указанным запросом. Sends an HTTP request with the specified request.

Отправляет HTTP-запрос с указанным запросом и маркером отмены. Sends an HTTP request with the specified request and cancellation token.

Отправляет HTTP-запрос с указанным запросом и маркером отмены. Sends an HTTP request with the specified request and cancellation token.

Отправляет HTTP-запрос. Sends an HTTP request.

Отправляет HTTP-запрос с указанным запросом, параметром завершения и маркером отмены. Sends an HTTP request with the specified request, completion option and cancellation token.

Отправка HTTP-запроса в качестве асинхронной операции. Send an HTTP request as an asynchronous operation.

Отправка HTTP-запроса в качестве асинхронной операции. Send an HTTP request as an asynchronous operation.

Отправка HTTP-запроса в качестве асинхронной операции. Send an HTTP request as an asynchronous operation.

Отправка HTTP-запроса в качестве асинхронной операции. Send an HTTP request as an asynchronous operation.

Возвращает строку, представляющую текущий объект. Returns a string that represents the current object.

Методы расширения

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос GET по указанному универсальному коду ресурса (URI) и возвращает значение, полученное в результате десериализации текста ответа в формате JSON в ходе асинхронной операции. Sends a GET request to the specified Uri and returns the value that results from deserializing the response body as JSON in an asynchronous operation.

Отправляет запрос POST по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в формате JSON в тексте запроса. Sends a POST request to the specified Uri containing the value serialized as JSON in the request body.

Отправляет запрос POST по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в формате JSON в тексте запроса. Sends a POST request to the specified Uri containing the value serialized as JSON in the request body.

Отправляет запрос POST по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в формате JSON в тексте запроса. Sends a POST request to the specified Uri containing the value serialized as JSON in the request body.

Отправляет запрос POST по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в формате JSON в тексте запроса. Sends a POST request to the specified Uri containing the value serialized as JSON in the request body.

Отправляет запрос PUT по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в виде JSON в тексте запроса. Send a PUT request to the specified Uri containing the value serialized as JSON in the request body.

Отправляет запрос PUT по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в виде JSON в тексте запроса. Send a PUT request to the specified Uri containing the value serialized as JSON in the request body.

Отправляет запрос PUT по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в виде JSON в тексте запроса. Send a PUT request to the specified Uri containing the value serialized as JSON in the request body.

Отправляет запрос PUT по указанному универсальному коду ресурса (URI), содержащий сериализованное значение value в виде JSON в тексте запроса. Send a PUT request to the specified Uri containing the value serialized as JSON in the request body.

Источник

Предотвращение атак с открытым перенаправлением в ASP.NET Core

Веб-приложение, которое перенаправляет на URL-адрес, указанный через запрос, например строку запроса или данные формы, потенциально может быть изменено для перенаправления пользователей на внешний вредоносный URL-адрес. Такое незаконное изменение называется атакой с открытым перенаправлением.

Каждый раз, когда логика приложения перенаправляется на указанный URL-адрес, необходимо убедиться, что URL-адрес перенаправления не был изменен. ASP.NET Core имеет встроенные функции, помогающие защитить приложения от атак с открытым перенаправлением (также называемых перенаправлением открытия).

Что такое атака с открытым перенаправлением?

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

Так как URL-адрес назначения указан в запросе QueryString, злоумышленник может изменить строку запроса. Неизмененная строка запроса может позволить сайту перенаправить пользователя на внешний вредоносный сайт. Этот метод называется атакой с открытым перенаправлением (или перенаправлением).

Пример атаки

Вероятно, пользователь считает, что первая попытка входа завершилась неудачно, а вторая попытка прошла успешно. Скорее всего, пользователь не знает, что их учетные данные скомпрометированы.

net core httpclient redirect. Смотреть фото net core httpclient redirect. Смотреть картинку net core httpclient redirect. Картинка про net core httpclient redirect. Фото net core httpclient redirect

Защита от атак с открытым перенаправлением

При разработке веб-приложений рассматривайте все предоставленные пользователем данные как ненадежные. Если в приложении есть функциональные возможности, которые перенаправляют пользователя на основе содержимого URL-адреса, убедитесь, что такие перенаправления выполняются локально в приложении (или на известном URL-адресе, а не в URL-адресе, который может быть предоставлен в строке запроса).

локалредирект

Используйте LocalRedirect вспомогательный метод из базового Controller класса:

LocalRedirect выдаст исключение, если указан нелокальный URL-адрес. В противном случае он ведет себя так же, как и Redirect метод.

ислокалурл

Используйте метод ислокалурл для проверки URL-адресов перед перенаправлением:

В следующем примере показано, как проверить, является ли URL-адрес локальным, перед перенаправлением.

IsLocalUrl Метод защищает пользователей от случайного перенаправления к вредоносному сайту. Вы можете записать в журнал сведения о URL-адресе, который был предоставлен, если нелокальный URL-адрес указан в ситуации, когда ожидался локальный URL-адрес. URL-адреса перенаправления журнала могут помочь при диагностике атак перенаправления.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *