Получение базового соединения было закрыто на HttpWebRequest

У меня есть приложение, написанное на VB.NET (НЕ asp.net, это консольное приложение Windows). Я пытаюсь вызвать URL-адрес (html-страницу) и вернуть ответ в строку. Ответ представляет собой прямой JSON, без каких-либо html-тегов. Он открывается с помощью { и закрывается с помощью }.

Я отлично создаю объект HttpWebRequest. Затем позвоните req.GetResponse(). Как только я это делаю, я получаю сообщение об ошибке The underlying connection was closed: The connection was closed unexpectedly.. Я гуглил и проверял stackoverflow и пробовал все, что нашел, что применимо (многое из этого связано с конфигурациями службы WCF, которые не применяются).

Вот мой код:

Public Function GetJSON(ByRef d As db.Device) As Boolean
    Try
        d.Url = "http://" & d.IpAddress & ini.doc.<svc>.<url>.Value

        Dim req As HttpWebRequest = HttpWebRequest.Create(d.Url)
        // req.Accept = "*/*"
        // req.Timeout = 30000
        // req.ReadWriteTimeout = 30000
        // req.KeepAlive = False
        // req.UseDefaultCredentials = True
        // req.CachePolicy = HttpWebRequest.DefaultCachePolicy
        // req.Proxy = HttpWebRequest.DefaultWebProxy
        // req.ProtocolVersion = New System.Version(1, 0)

        Dim rsp As HttpWebResponse = req.GetResponse()

        Return True
    Catch ex As Exception
        Log(ex.Message)
        Return False
    Finally
        rsp = Nothing
        req = Nothing
    End Try
End Function

Закомментированные строки (неправильный стиль комментария, но поэтому SO разберет его правильно) - это все, что я пробовал до сих пор, основываясь на том, что я нашел в Интернете. Ни один из них не исправил. Я проверил правильность создаваемого URL-адреса; если я вызываю точно такой же URL в своем браузере, он возвращает точно ожидаемый ответ.

Я пробовал использовать wireshark... и я вижу, что фактически ожидаемые, полные данные возвращаются в выводе акулы, а затем несколько строк, а затем красная строка, которая говорит: http > 51943 [RST] Seq=1607 Win=0 Len=0, которая является последней строкой, отображаемой перед . NET выдает ошибку.

Я также попытался включить System.Net трассировку/регистрацию для каждого сообщения здесь, на SO, и в выходном файле я вижу, что все ожидаемые данные JSON действительно возвращаются, но после того, как они возвращаются, они выбрасывают эти строки в журнале трассировки .NET:

System.Net.Sockets Verbose: 0 : [7040] Exiting Socket#60467532::Receive()   -> 1605#1605
System.Net.Sockets Verbose: 0 : [7040] Socket#60467532::Receive()
System.Net.Sockets Verbose: 0 : [7040] Data from Socket#60467532::Receive
System.Net.Sockets Verbose: 0 : [7040] 00000000 :                                                 : 
System.Net.Sockets Verbose: 0 : [7040] Exiting Socket#60467532::Receive()   -> 0#0
System.Net.Sockets Verbose: 0 : [7040] Socket#60467532::Dispose()
System.Net Error: 0 : [7040] Exception in the HttpWebRequest#27806816:: - The underlying connection was closed: The connection was closed unexpectedly.
System.Net Error: 0 : [7040] Exception in the HttpWebRequest#27806816::GetResponse - The underlying connection was closed: The connection was closed unexpectedly.

Любые идеи, куда идти дальше, чтобы попытаться понять это? Мы считываем эти данные с некоторых сенсорных устройств для мониторинга окружающей среды, и они дали нам этот URL для использования.

Две вещи, которые меня действительно заводят и смущают, заключаются в следующем:
а) он отлично работает при вызове в браузере
б) трассировка WireShark и .NET показывает все данные на самом деле ЯВЛЯЕТСЯ возвращается, и фреймворк по какой-то причине исключает ПОСЛЕ получения всех данных!

Само WebException используется очень мало, так как его InnerException имеет значение null, а его статус просто говорит «ConnectionClosed {8}».

Заранее спасибо!!!

ОБНОВЛЕНИЕ 18/08 1130: я также попытался использовать только System.Net.WebRequest вместо HttpWebRequest. Это тоже не имело никакого значения.

ОБНОВЛЕНИЕ 18/08 1222: я только что попытался переключить свой код вместо использования [Http]Web[Request|Response] на затемнение объекта WebClient и использовать его метод DownloadString(). Однако это также выдает точно такую ​​же ошибку.

ОБНОВЛЕНИЕ 18/08 1230: Пробовал использовать My.Computer.Network.DownloadFile() - также получил ту же ошибку закрытия соединения.


person eidylon    schedule 16.08.2010    source источник
comment
Вот вставка моего полного файла трассировки network.log .NET: pastebin.com/QfY05a11 . Вы можете увидеть, что все данные JSON возвращаются в строке 41.   -  person eidylon    schedule 18.08.2010
comment
Вот вставка журнала трафика Wireshark: pastebin.com/0hbEQerc . Вы можете видеть, что данные возвращаются в строке 607.   -  person eidylon    schedule 18.08.2010


Ответы (6)


Можете ли вы опубликовать все содержимое журнала трассировки на pastebin.com и разместить ссылку здесь?

Вы можете получить это исключение, потому что сервер может сказать в заголовке «Content-Length», что он отправляет N байтов сущности, но на самом деле отправляет меньше N байтов и закрывает соединение.

Отвечать:

Спасибо за данные. Судя по трассировке и трассировке wireshark, сервер не отправляет никаких заголовков ответа, а отправляет данные напрямую. Это нарушение протокола HTTP. Вот почему клиент выдает исключение.

person feroze    schedule 17.08.2010
comment
Да, из журнала трассировки я вижу, что сервер не отвечает ни одним допустимым заголовком ответа HTTP. Сервер должен сначала отправить заголовки ответа HTTP, а затем отправить полезную нагрузку JSON. Это проблема - person feroze; 18.08.2010
comment
Также есть ошибка в вашем коде. Вы не удаляете объект HttpWebResponse, полученный при вызове GetResponse(). Вам нужно вызвать Dispose() для этого объекта, иначе у вас закончатся подключения к серверу. - person feroze; 18.08.2010
comment
Спасибо за информацию. Я должен исправить код завтра в офисе. У меня ДЕЙСТВИТЕЛЬНО есть вопрос (который, я думаю, я смогу узнать и завтра)... будет ли работать переход только на System.Net.WebRequest, а не на HttpWebRequest, учитывая, что тогда теоретически он не должен искать заголовки HTTP? - person eidylon; 18.08.2010
comment
Здравствуйте, спасибо за вашу помощь до сих пор. Я пытался использовать простой объект WebRequest вместо HttpWebRequest, однако это не помогло. Должен быть какой-то способ сказать ему принять это, может быть, добавив заголовки или что-то еще в мой запрос? Я также вставил код для удаления моего объекта Response, и на самом деле у него нет метода Dispose(), поэтому в блоке finally я просто установил для rsp и req значение Nothing. - person eidylon; 18.08.2010
comment
Думаю, я не ясно выразился. Изменение кода клиента не решит реальной проблемы. Настоящая проблема заключается в том, что сервер плохо себя ведет - он отправляет тело ответа без отправки заголовков ответа. Вы должны исправить сервер, если у вас есть код для него. Использование WebRequest вместо HttPWebRequest не исправит ситуацию. - person feroze; 18.08.2010
comment
ТАКЖЕ, если вы не можете исправить сервер, я бы посоветовал вам напрямую использовать Socket/TcpClient и прочитать ответ JSON. - person feroze; 18.08.2010
comment
Спасибо, что указали мне направление TcpClient... с этим я смог покопаться и заставить его работать идеально! :) . CheerZ! - person eidylon; 20.08.2010
comment
@feroze - относительно утилизации объекта HttpWebResponse: можно ли его утилизировать? Intellisense не предоставляет метод .Dispose(). - person JYelton; 03.09.2010
comment
Да, у HttpWebResponse есть метод Dispose(). Он унаследован от WebResponse. Посмотрите это в документах. - person feroze; 04.09.2010

Это помогает мне. Я надеюсь, что это поможет кому-то.

Сразу после создания объекта HttpWebRequest добавьте эту строку.

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3;

Это означает, что в качестве протокола безопасности указывается Secure Socket Layer (SSL) 3.0.

http://support.microsoft.com/kb/915599

person vnRock    schedule 13.12.2010

Вот как у меня это заработало... Спасибо feroze за то, что указал мне правильное направление!
(присуждаются баллы)

Public Function GetJSON(ByRef d As db.Device) As Boolean
    Try
        Dim tcp = New TcpClient()
        tcp.Connect(d.IpAddress, 80)

        Dim ns = tcp.GetStream()

        Dim req As Byte() = System.Text.Encoding.ASCII.GetBytes(
            "GET /getdata.htm HTTP/1.1" & vbCrLf & vbCrLf
        )
        ns.Write(req, 0, req.Length)

        Dim rsp(2048) As Byte, rcv As Integer
        Do
            rcv = ns.Read(rsp, 0, rsp.Length)
            d.JSON &= System.Text.Encoding.ASCII.GetString(rsp, 0, rcv)
        Loop Until rcv = 0

        tcp.Close()

        Return True
    Catch ex As Exception
        Log(ex.Message)
        Return False
    End Try
End Function
person eidylon    schedule 19.08.2010
comment
tcp.Close() должен быть вызван изнутри, наконец, иначе он не будет вызван, если перед вызовом .Close() возникнет исключение. - person sharptooth; 11.08.2017

Проверьте задержку запроса. Если это больше нескольких мс, то стоит отключить алгоритм Нейгла.

 ServicePointManager.UseNagleAlgorithm = false;
person NMech    schedule 06.02.2014

У меня была такая же проблема с запросом БЕЗ тела. В моем случае установка ContentLength на НОЛЬ устранила проблему.

person Eduardo Patriota Gusmão Soares    schedule 03.10.2014

В моем случае проблема заключалась в том, что мы использовали «http://..» в качестве адреса службы вместо «https://»…

person ozgur    schedule 25.01.2017