Как сделать так, чтобы трафик ретрансляции HttpClient отображался в Fidder или Charles?

У меня есть простой проект веб-API, основанный на этом примере: http://aspnet.codeplex.com/sourcecontrol/latest#Samples/WebApi/RelaySample/Program.cs

Однако в примере выше реле работает с локальным сервером, в моем проекте реле работает с внешним веб-сервером с реальным адресом; компанияX.com

Я использую службу ретрансляции (или службу веб-прокси) через браузер, например, в запросе браузера relayService.com/companyX. Служба ретрансляции отвечает данными с внешнего сайта companyX.com.

Ретранслятор работает отлично, однако некоторые заголовки неверны, и мне нужно посмотреть, что HttpClient отправляет на удаленный сервер companyX.com.

В fiddler или Charles указан только запрос/ответ от моего браузера к relayService.com, запрос/ответ от HttpClient к relayService.com никогда не появляется.

relayService.com работает локально на моей машине, в IIS7 я использую файл hosts для направления трафика на relayService.com.

Я пробовал несколько вариантов следующего при создании HttpClient:

        var clientHandler = new HttpClientHandler
        {
            CookieContainer = cookies,
            UseCookies = true,
            UseDefaultCredentials = false,
            Proxy = new WebProxy("http://localhost:8888"),
            UseProxy = true,
            AutomaticDecompression = DecompressionMethods.GZip, 
            AllowAutoRedirect = false, 
            ClientCertificateOptions = ClientCertificateOption.Automatic
        };


        HttpClient client = new HttpClient(clientHandler);

ОБНОВИТЬ

Если я изменю UseProxy = false, служба продолжит работать, когда Fiddler открыт или закрыт.

С UseProxy = true служба выйдет из строя, если скрипач открыт, я получаю следующую ошибку:

Object reference not set to an instance of an object.

at System.DomainNameHelper.IdnEquivalent(String hostname) at System.Net.HttpWebRequest.GetSafeHostAndPort(Uri sourceUri, Boolean addDefaultPort, Boolean forcePunycode) at System.Net.HttpWebRequest.GenerateProxyRequestLine(Int32 headersSize) at System.Net.HttpWebRequest.SerializeHeaders() at System.Net.HttpWebRequest.EndSubmitRequest() at System.Net.Connection.CompleteConnection(Boolean async, HttpWebRequest request)

С UseProxy = true и скрипач ЗАКРЫТ, я получаю следующую (очевидную) ошибку:

No connection could be made because the target machine actively refused it 127.0.0.1:8888

В том же решении я использую HttpWebRequest для загрузки данных из Интернета, и это отображается в Fiddler, поэтому, похоже, это проблема с HttpClient.GetAsync().

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

Я боролся с этим весь день, любая помощь будет высоко оценена.

Напомним: * relayService.com работает локально на моей машине в IIS7.

  • файл hosts имеет "127.0.0.1 relayService.com"

  • relayService.com — это сайт веб-API MVC, который использует HttpClient.GetAsync() для загрузки контента из Интернета.

  • Fiddler/Charles работает локально на той же машине

  • трафик браузера на локальный relayService.com отображается в Fiddler/Charles

  • HttpClient.GetAsync() для живого веб-трафика не отображается в Fiddler/Charles

  • Fiddler/Charles — обновленные версии.

Спасибо еще раз


person MCM    schedule 24.07.2013    source источник


Ответы (2)


Вам ничего не нужно в файле HOSTS, если вы используете Fiddler; вы можете использовать инструменты Fiddler > HOSTS для перенаправления трафика в любое место.

При попытке захвата трафика из служебной учетной записи (например, учетной записи ASP.NET) обычно требуется настроить эту учетную запись для использования прокси-сервера; см. http://fiddler2.com/blog/blog/2013/01/08/capturing-traffic-from-.net-services-with-fiddler, чтобы узнать об этом подробнее. В этом случае вам не нужно настраивать прокси-объект непосредственно в коде.

Показанное вами исключение предполагает наличие ошибки в функции GenerateProxyRequestLine. Есть ли какие-либо изменения, если вы обновите это: new WebProxy("http://localhost:8888"); до new WebProxy("127.0.0.1", 8888);?

Вообще говоря, приложения .NET будут обходить прокси-сервер для URL-адресов, указывающих на //localhost или //127.0.0.1, поэтому при отладке с помощью Fiddler обычно используется URL-адрес службы //localhost.fiddler, чтобы трафик всегда направлялся на прокси.

person EricLaw    schedule 25.07.2013
comment
Привет Эрик, спасибо за ответ. Я уже пробовал эти предложения. Тем не менее, я это исправил! У меня нет объяснения, почему решение работает, но оно работает. Я был бы признателен, если бы вы могли пролить какую-либо информацию. Спасибо. - person MCM; 26.07.2013

Я исправил проблему, сделав HttpClient статическим.

Это отлично работает (для функциональности программы), но имеет проблему со скрипачом, описанную выше, когда попытка использовать прокси выдает ошибку:

private HttpClient _client()
{

    var clientHandler = new HttpClientHandler
    {
        UseCookies = true,
        UseDefaultCredentials = false,
        Proxy = new WebProxy("http://localhost:8888"),
        UseProxy = true,
        AutomaticDecompression = DecompressionMethods.GZip,
        AllowAutoRedirect = true,
        ClientCertificateOptions = ClientCertificateOption.Automatic
    };

    HttpClient client = new HttpClient(clientHandler);
    client.Timeout = TimeSpan.FromMinutes(20);

    return client;
}

Клиент был создан с помощью:

using (HttpResponseMessage serviceResponse = await _client().GetAsync(getURL(), HttpCompletionOption.ResponseHeadersRead))
    {
                // Return response

    }

Однако приведенное ниже также работает, и весь трафик отображается в Fiddler!

private static readonly HttpClientHandler _clientHandler = new HttpClientHandler()
{
    //CookieContainer = cookies,
    UseCookies = true,
    UseDefaultCredentials = false,
    Proxy = new WebProxy("http://localhost:8888"),
    UseProxy = false,
    AutomaticDecompression = DecompressionMethods.GZip,
    AllowAutoRedirect = false,
    ClientCertificateOptions = ClientCertificateOption.Automatic, 
};

//Create a shared instance of HttpClient and set the request timeout
private static readonly HttpClient _client = new HttpClient(_clientHandler)
{
    Timeout = TimeSpan.FromMinutes(20)
};

Клиент был создан с помощью (единственное отличие заключается в удалении '()' после _client выше):

using (HttpResponseMessage serviceResponse = await _client.GetAsync(getURL(), HttpCompletionOption.ResponseHeadersRead))
    {
                // Return response

    }

Я понятия не имею, почему это работает. Любое понимание будет оценено.

Спасибо,

person MCM    schedule 26.07.2013
comment
Тот факт, что создание статического объекта исправляет ситуацию, подразумевает, что объект HttpClient был собран мусором до того, как был возвращен ответ. Что касается того, почему это так, я боюсь, что недостаточно знаю о машине состояний, создаваемой при использовании асинхронного метода. - person EricLaw; 26.07.2013
comment
Конечный автомат, сгенерированный с помощью функций async/await, очень похож на то, как работают замыкания и итераторы, в том смысле, что все, на что ссылаются ниже вызовов await, по-прежнему сохраняет свою ссылку и предотвращает сборку мусора, но если вы больше никогда не используете клиентский объект, это может объяснить это. Тем не менее, HttpClient и HttpClientHandler являются IDisposable, поэтому вам обязательно следует обернуть создание/использование в операторы использования, которые заставят ссылку ниже ожидания существовать в конечном автомате (для удаления в сгенерированном блоке finally). - person TheXenocide; 21.05.2014