Тайм-Ауты HttpWebRequest После Десяти Последовательных Запросов
Я пишу веб-искатель для конкретного сайта. Приложение представляет собой VB.Net приложение Windows Forms, которое не использует несколько потоков - каждый веб-запрос является последовательным. Однако после десяти успешных попыток извлечения страницы каждый последующий запрос заканчивается.
Я рассмотрел аналогичные вопросы, уже опубликованные здесь на SO, и внедрил рекомендуемые методы в свою процедуру GetPage, показанную ниже:
Public Function GetPage(ByVal url As String) As String
Dim result As String = String.Empty
Dim uri As New Uri(url)
Dim sp As ServicePoint = ServicePointManager.FindServicePoint(uri)
sp.ConnectionLimit = 100
Dim request As HttpWebRequest = WebRequest.Create(uri)
request.KeepAlive = False
request.Timeout = 15000
Try
Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse)
Using dataStream As Stream = response.GetResponseStream()
Using reader As New StreamReader(dataStream)
If response.StatusCode <> HttpStatusCode.OK Then
Throw New Exception("Got response status code: " + response.StatusCode)
End If
result = reader.ReadToEnd()
End Using
End Using
response.Close()
End Using
Catch ex As Exception
Dim msg As String = "Error reading page """ & url & """. " & ex.Message
Logger.LogMessage(msg, LogOutputLevel.Diagnostics)
End Try
Return result
End Function
Я что-то пропустил? Разве я не закрываюсь или избавление от объекта, который должен быть? Кажется странным, что это всегда происходит после десяти последовательных запросов.
Примечания:
В конструкторе для класса, в котором находится этот метод, у меня есть следующее:
ServicePointManager.DefaultConnectionLimit = 100
Если я установлю KeepAlive в true, тайм-ауты начнутся после пяти запросов.
Все запросы на страницы в одном и том же домен.
EDIT
Я добавил задержку между каждым веб-запросом от двух до семи секунд, чтобы не было похоже, что я" забиваю " сайт или пытаюсь атаковать DOS. Однако проблема все равно возникает.
6 ответов:
Я думаю, что сайт имеет какую-то защиту DOS, которая срабатывает, когда на него попадает несколько запросов rapis. Вы, возможно, захотите попробовать установить юзерагент на запросы WebRequest.
Я столкнулся с этим вопросом сегодня, и моя резолюция состояла в том, чтобы гарантировать, что ответ был закрыт во все времена.
Я думаю, что вам нужно поставить в ответе.Закройте (), прежде чем вы бросите свое исключение внутри using.
Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse) Using dataStream As Stream = response.GetResponseStream() Using reader As New StreamReader(dataStream) If response.StatusCode <> HttpStatusCode.OK Then response.Close() Throw New Exception("Got response status code: " + response.StatusCode) End If result = reader.ReadToEnd() End Using End Using response.Close() End Using
Я использовал следующее решение, и оно работает для меня. Надеюсь, вам это тоже поможет.
Объявляем" глобальными " по форме переменные.
HttpWebRequest myHttpWebRequest; HttpWebResponse myHttpWebResponse;Затем всегда используйте
myHttpWebResponse.Close();после каждого соединения.myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse(); myHttpWebResponse.Close();
Я знаю, что это старый вопрос, но у меня недавно была эта проблема (из-за моей целевой среды, использующей 4.0 и не допускающей никаких внешних ссылок на сборки)
Я немного покопался, однако, и нашел своего рода исправление, и это очень интересно с точки зрения внутренней работы .NET
ServicePointManager.DefaultConnectionLimit = 100;ServicePointManager внутренне обрабатывает фактический HTTP-запрос, созданный несколькими объектами HttpWebRequest ..проблема в том, что они не закрываются автоматически, а HttpWebRequest-нет. получает мусор, собранный немедленно
Итак, я нашел кое-что очень интересное – если я делаю HttpWebRequest переменной уровня экземпляра и заставляю сборку мусора после переключения ссылки ... это работает (без DefaultConnectionLimit = 100 hack)
private HttpWebRequest Request { get; set; } public void MyMethod() { Request = (HttpWebRequest)HttpWebRequest.Create("http://myUrl"); GC.Collect(); GC.WaitForFullGCComplete(); }До этого я каждый раз создавал новую локальную переменную в методе. Это, казалось, решило мою проблему-вероятно, немного слишком поздно, чтобы помочь вам, но я подумал, что поделюсь, если кто-нибудь еще столкнется с этим
Если сервер использует базу данных и не закрывает каждое соединение с базой данных должным образом, вы можете получить сообщение об ошибке (например, statuscode 502) при максимальном значении. соединение ограничено (до истечения времени ожидания соединения с базой данных). Решением в этом случае является только "спящий" поток webrequest в течение заданного времени. Кроме того, вы должны убедиться, что каждый поток запросов и ответов закрывается после обработки (в лучшем случае с помощью оператора Using):
MyRequest.Соединение = " Закрыть"; заставит сервер закрыть соединение, которое заставит диспетчер соединений закрыть соединение тоже.
Comments