Веб-искателю .NET необходимо измерить время до первого байта HttpWebResponse

#.net #httpwebrequest #httpresponse #webrequest #httpwebresponse

#.net #httpwebrequest #httpresponse #веб-запрос #httpwebresponse

Вопрос:

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

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

 HttpWebResponse webResponse = null;

var stopWatch = new Stopwatch();
stopWatch.Start();
try
{
    var webRequest = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
    webRequest.Method = "get";

    webRequest.AllowAutoRedirect = false;
    webRequest.UserAgent = userAgent;
    webRequest.Accept = "*/*";
    webRequest.KeepAlive = true;
    webRequest.CookieContainer = CookieContainer;

    webResponse = (HttpWebResponse)webRequest.GetResponse();

    responseTimeToFirstByte = Convert.ToInt32(stopWatch.ElapsedMilliseconds);

    using (var responseStream = new StreamReader(webResponse.GetResponseStream(), System.Text.Encoding.ASCII))
    {
        bodyContent = responseStream.ReadToEnd();
        stopWatch.Stop();
    }

    webResponse.Close();
    responseTimeFull = Convert.ToInt32(stopWatch.ElapsedMilliseconds);
}
  

Ответ №1:

Вы ничего не упускаете. Просто платформа уведомляет об ответе, когда он уже буферизован и проанализирован, когда он уже есть.

HttpWebResponse Объект уже имеет информацию о наборе HTTP-заголовков, поэтому данные уже были прочитаны и проанализированы. Возможно, отправляя огромный файл, вы можете обнаружить разницу, и я не совсем уверен.

Если вы хотите измерить TFB, вы можете использовать Socket или лучше a TcpClient и отправить обработанный HTTP-запрос, а затем измерить время до получения данных обратно:

 Byte[] buffer = new Byte[1024];
Int32 readed = -1;
TcpClient client = new TcpClient();
Stopwatch watch = new Stopwatch();
List<Int64> readTimes = new List<Int64>();

watch.Start();
await client.ConnectAsync(<IP address>, <Port>);
using(var stream = client.GetStream())
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(stream, Encoding.ASCII))
{
    sw.WriteLine("GET /the/path/to/your/resource HTTP/1.1");
    sw.WriteLine("Host: yourdomainname.com");
    sw.WriteLine("Accept: text/html,application/xhtml xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
    sw.WriteLine();
    await sw.FlushAsync();

    while(readed != 0)
    {
        readed = await stream.ReadAsync(buffer,0,buffer.Length);
        readTimes.Add(watch.ElapsedMilliseconds);
        ms.Write(buffer,0,readed);
    }

    watch.Stop();
}
  

(Предупреждение, этот код не тестировался)

В этом коде первым значением в «readTimes» будет ваш TFB, а последним — общее время.

Приветствия.

Комментарии:

1. @vortola — в вашем примере, почему вы используете ConnectAsync? Какая разница, когда вы ожидаете результат в той же строке?

2. Разница в том, что поток выполнения будет выпущен для выполнения чего-либо в другом месте, пока процесс подключения не завершится, затем поток вернется, чтобы продолжить работу с остальной частью метода. Вы можете использовать simple Connect и Flush , вероятно, это не будет иметь значения, если вы не выполняете какие-либо параллельные интенсивные действия.