HttpHandler ответ никогда не возвращается - PullRequest
3 голосов
/ 11 ноября 2008

У нас есть довольно сложный httphandler для обработки изображений. В основном он передает любую часть изображения в любом размере, который запрашивается. Некоторые клиенты используют этот обработчик без проблем. Но у нас есть одно местоположение, которое создает нам проблемы, и теперь оно также создает проблемы в моей среде разработки.

В результате клиент никогда ничего не получает по некоторым запросам. Так что запросы 1 и 2 в порядке, но запросы 3 и 4 никогда не заканчиваются.

  • Во время отладки я вижу, что сервер готов и завершил запрос.
  • Однако клиент все еще ожидает результата (отладка с помощью fiddler2 показывает, что ответ не получен)

Код, который мы используем для потоковой передачи изображения:

        if (!context.Response.IsClientConnected)
        {
            imageStream.Close();
            imageStream.Dispose();
            return;
        }

        context.Response.BufferOutput = true;
        context.Response.ContentType = "image/" + imageformat;

        context.Response.AppendHeader("Content-Length", imageStream.Length.ToString());

        if (imageStream != null && imageStream.Length > 0 && context.Response.IsClientConnected)
            context.Response.BinaryWrite(imageStream.ToArray());

        if (context.Response.IsClientConnected)
            context.Response.Flush();

        imageStream.Close();
        imageStream.Dispose();

imageStream - это MemoryStream с содержимым изображения.

После вызова response.Flush () мы делаем еще одну очистку и записываем резюме в журнал событий.

Мы также вызываем GC.Collect () после каждого запроса, потому что объекты, которые мы используем в памяти, становятся очень большими. Я знаю, что это плохая практика, но может ли это доставить нам неприятности?

Проблемы с невозможностью возврата запросов возникают как в IIS 5 (Win XP), так и в IIS 6 (Win 2003), мы используем .NET Framework v2.

Ответы [ 4 ]

4 голосов
/ 11 ноября 2008

Во-первых, есть более эффективные способы работы с потоками, которые используют массив для всего этого (т. Е. MemoryStream может здесь быть ненужным).

Я бы предусмотрел цикл:

const int BUFFER_SIZE = 4096; // pick your poison
bute[] buffer = new byte[BUFFER_SIZE];
int bytesRead;

while((bytesRead = inStream.Read(buffer, 0, BUFFER_SIZE)) > 0)
{
    outStream.Write(buffer, 0, bytesRead);
}

Вы также должны сделать это с отключенной буферизацией (.Response.BufferOutput = false).

По поводу проблемы, я подозреваю, что вы не написали достаточно данных / закрыли ответ (.Response.Close()).

2 голосов
/ 11 ноября 2008

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

При использовании HttpWebResponse вы должны располагать либо этот объект, либо поток, возвращенный его методом GetResponseStream, для завершения соединения.

Ваш код был очень запутанным. Вы включили буферизацию, установили длину содержимого и использовали сброс. Это приводит к некоторым странным заголовкам HTTP. Обычно с включенной буферизацией вы оставляете настройку заголовка Content-Length для ASP.NET для обработки.

Когда вы используете flush, ASP.NET предполагает, что вы впоследствии можете отправить больше данных. В этом случае он будет использовать чанкованный перевод. Как только ответ завершен, для окончательного фрагмента отправляется окончательный набор заголовков, каждый из которых имеет свой собственный заголовок длины, а общая длина контента получается из них. Первый блок должен , а не иметь заголовок Content-Length, однако ваш код добавляет этот заголовок.

Если вы отключите буферизацию и накачаете байты в выходной поток самостоятельно , то вам следует установить заголовок Content-Length самостоятельно, потому что эффективное отключение буфера означает, что вы берете на себя ответственность именно за то, что отправляется клиенту , Код Марка - простой пример такого насоса, хотя я бы использовал больший буфер, или для MemoryStream метод WriteTo был бы более эффективным.

2 голосов
/ 11 ноября 2008

Сборка мусора не должна быть проблемой. Почему вы устанавливаете BufferOutput в true, хотя? Учитывая, что вы просто хотите записать данные напрямую, я бы подумал, что было бы более целесообразно установить их в false.

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

0 голосов
/ 11 ноября 2008

Мы также использовали веб-запросы для сбора дополнительной информации. Те блокировали связи. Помогая в использовании WebResponses, добились цели.

using (HttpWebResponse test_resp = (HttpWebResponse)test_req.GetResponse())
{
}

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

...