Подтвердить что ты не робот

HttpRequestException - проблема с клиентом или сервером?

Недавно я реализовал некоторый код для использования REST Api, используя класс HttpClient.

using (var client = new HttpClient() { BaseAddress = new Uri(@"https://thirdparty.com") })
{
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(...);

    var uri = new Uri(@"rest/api/foo", UriKind.Relative);
    var content = new StringContent(json.ToString());

    using (var response = await client.PostAsync(uri, content))
    {
        // etc ...
    }
}

Этот код, казалось, отлично справлялся как с тестовыми, так и с производственными средами (каждый из которых обращался к тестовому/производственному uri). В последнее время мы начали получать исключение HttpRequestException в производственной среде: System.Net.Http.HttpRequestException: Error while copying content to a stream.

Это показалось немного странным, поэтому я использовал Postman для отправки того же сообщения, и он работал отлично. Я не был уверен, почему наш код не работает, и Почтальон работает. Я изменил параметр в json-данных (состояние от "NY" до "NV" ), и наш .NET-код работал нормально - конечно, мы не можем просто отправлять неверные данные json, поэтому это не решение; это было скорее наблюдением, что тот же самый код отлично работал с различным контентом.


Интересно, что есть два изменения кода, которые мы могли бы сделать, чтобы решить эту проблему. Во-первых, Postman способен генерировать рабочий код С# с помощью RestSharp. В качестве альтернативы я нашел ответ из другого вопроса, указывающего на использование HttpVersion 1.0:

using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
{
    request.Version = HttpVersion.Version10;
    request.Content = new StringContent(json.ToString());

    using (var response = await client.SendAsync(request))
    {
        // etc ...
    }
}

Сбивая с толку часть, Postman использует версию HTTP/1.1. Итак, вкратце:

  • Если мы изменим данные json (штат США от "NY" до "NV" ), код работает.
  • Тот же самый точный json и код работают против тестового uri.
  • Смена кода для использования пакета RestSharp работает.
  • Выполняется изменение кода для использования HTTP/1.0 вместо HTTP/1.1.

Почему Postman способен работать с использованием HTTP/1.1, но HttpClient терпит неудачу? Это проблема с нашим клиентом (код работает для других штатов США)? Это ошибка в .NET Framework? Что-то не так с реализацией/хостингом REST Api от третьего лица?


Почтовые заголовки:

POST rest/api/foo HTTP/1.1
Host: thirdparty.com
Content-Type: application/json
Authorization: Basic SOME_ENCRYPTED_USER_PASS
Cache-Control: no-cache
Postman-Token: 2fa5b5a0-b5d3-bd4c-40f0-d2b55b60316b

Пример Json:

{
    "stateCode": "NY",
    "packageID": "58330",
    "name": "58330-PRI-1",
    "documents": [
        {
            "type": "SPECIAL",
            "name": "Sample Document",
            "documentID": "3569976"
        }
    ],
    "descriptions": [
        {
            "city": "New York",
            "state": "NY"
        }
    ]
}

StackTrace:

AggregateException: One or more errors occured.
HttpRequestException: Error while copying content to a stream.
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
SocketException: An existing connection was forcibly closed by the remote host.
4b9b3361

Ответ 1

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

Попробуйте неявно сообщать серверу не использовать кешированные значения...

using (var client = new HttpClient() { BaseAddress = new Uri(@"https://thirdparty.com") })
{
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(...);

    var uri = new Uri(@"rest/api/foo", UriKind.Relative);
    var content = new StringContent(json.ToString());

    client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache");

    using (var response = await client.PostAsync(uri, content))
    {
        // etc ...
    }
}

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

Ответ 2

У вас есть антивирус/брандмауэр на компьютере, на котором запущен HttpClient? В прошлом у меня были проблемы с AVG, Mcafee, Norton и другими, которые молча блокировали запросы. Его довольно сложно выяснить, где именно, но может быть вкладка, где контролируются порты, отключение/отключение этого может помочь выявить проблему. Если это так, правильным решением является получение вашего "thirdparty.com" в белом списке соответствующих поставщиков/с.

Возможно, стоит посмотреть на заголовки ответов с вашего сервера? Не могли бы вы добавить их в свой вопрос? Только потому, что в прошлом я нашел заголовки Content-Security-Policy, предотвращающие выполнение некоторых моих запросов?