Wep API не может вернуть данные из вызова HttpClient - PullRequest
0 голосов
/ 28 мая 2019

Мне не удалось выяснить, почему возникает следующая проблема:

Я создал простой веб-контроллер API (.Net Framework 4.6.1)

public class TestController : ApiController
{
    // GET api/<controller>
    public async Task<string> Get()
    {
        var url = "http://api.plos.org/search?q=title:DNA";
        using (var httpClient = new HttpClient())
        {
            using (var response = await httpClient.GetAsync(url))
            {
                using (var content = response.Content)
                {
                    var result = await content.ReadAsStringAsync();
                    return result;

                }
            }
        }
    }
}

КогдаПосле запуска кода выше примерно через 20 секунд выдается следующая ошибка.

{
    "Message": "An error has occurred.",
    "ExceptionMessage": "An error occurred while sending the request.",
    "ExceptionType": "System.Net.Http.HttpRequestException",
    "StackTrace": "   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n   at restapitest2.Controllers.TestController.<Get>d__0.MoveNext() in C:\\restapitest2\\restapitest2\\Controllers\\TestController.cs:line 19\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Threading.Tasks.TaskHelpersExtensions.<CastToObject>d__1`1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()",
    "InnerException": {
        "Message": "An error has occurred.",
        "ExceptionMessage": "Unable to connect to the remote server",
        "ExceptionType": "System.Net.WebException",
        "StackTrace": "   at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)\r\n   at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)",
        "InnerException": {
            "Message": "An error has occurred.",
            "ExceptionMessage": "A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 216.74.38.80:80",
            "ExceptionType": "System.Net.Sockets.SocketException",
            "StackTrace": "   at System.Net.Sockets.Socket.InternalEndConnect(IAsyncResult asyncResult)\r\n   at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)\r\n   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)"
        }
    }
}

При создании веб-контроллера API dotnet core тот же код работает нормально.

Это то, что точкаЧистый основной код выглядит следующим образом.

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    // GET api/values
    [HttpGet]
    public async Task<ActionResult<string>> Get()
    {
        var url = "http://api.plos.org/search?q=title:DNA";
        using (var httpClient = new HttpClient())
        {
            using (var response = await httpClient.GetAsync(url))
            {
                using (var content = response.Content)
                {
                    var result = await content.ReadAsStringAsync();
                    return result;

                }
            }
        }
    }
}

Странно то, что если я использую внутренний URL, оба решения API возвращают данные.

Любая помощь будет принята

Ответы [ 2 ]

2 голосов
/ 28 мая 2019

Вы уверены, что не находитесь за прокси-сервером?

Вы уверены, что ваш DNS-сервер может искать api.plos.org?

Более подробно проверьте свое исключение, проверив его внутренние исключения.поможет вам понять, что проблема с DNS или проблема с прокси.

Если вы находитесь за прокси-сервером, не забудьте установить прокси для HttpClient.

Обновление 1:

Попытка подключения не удалась, потому что подключенная сторона не ответила должным образом через некоторое время, или не удалось установить соединение, так как подключенный хост не смог ответить 216.74.38.80:80

Я сталкивался с этой ошибкой каждый раз, когда получал прокси на моей машине.Поскольку вы сказали «если вы запускаете fiddler, все работает нормально», я предполагаю, что вам нужно удалить настройки прокси из windows Lan Settings.

  1. . В run введите inetcpl.cpl и нажмите enter.
  2. Перейдите на вкладку Connections.
  3. В нижней части диалогового окна есть кнопка Lan Settings.Нажмите на него.
  4. В диалоговом окне настроек локальной сети убедитесь, что вы сняли все флажки, особенно use proxy for your lan.

Не по теме рекомендации:

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

public class GoodController : ApiController
{
    // OK
    private static readonly HttpClient HttpClient;

    static GoodController()
    {
        HttpClient = new HttpClient();
    }
}
0 голосов
/ 28 мая 2019

Поскольку другие отмечали, что код работает, что может быть связано с проблемами HTTPS или с прокси-сервером, я переписал следующий код, чтобы включить HTTPS в URL-адрес

 [HttpGet]
    public async Task<ActionResult<string>> Get()
    {
        var url = "https://api.plos.org/search?q=title:DNA";

        var request = new HttpRequestMessage(HttpMethod.Get, url);

        var httpClient = new HttpClient();

        using (var response = await httpClient.SendAsync(request))
        {
            var content = response.Content.ReadAsStringAsync();

            response.EnsureSuccessStatusCode();

            return Ok(content);
        }
    }

Но ябудет использовать IHttpClientFactory из-за проблем, которые он решает для сокетов, а не HttpClient.

Чтобы использовать IHttpClientFactory, выполните следующее

Добавьте службу в ConfigureServices.cs

  services.AddHttpClient();

затем вставьте вызов в конструктор

    private readonly IHttpClientFactory _clientFactory;

    public ValuesController(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }

, тогда ваш вызов API будет выглядеть следующим образом:

var url = "https://api.plos.org/search?q=title:DNA";

        var request = new HttpRequestMessage(HttpMethod.Get, url);

        var httpClient = _clientFactory.CreateClient();

        using (var response = await httpClient.SendAsync(request))
        {
            var content = response.Content.ReadAsStringAsync();

            response.EnsureSuccessStatusCode();

            return Ok(content);
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...