Я не думаю, что это имеет отношение к безопасности. Ошибка 500 - это ошибка на стороне сервера. Что-то в запросе, сгенерированном XmlReader.Create (url), сбивает с толку веб-сайт ibm. Если бы это была просто проблема безопасности, как предложено в вашем вопросе, то вы ожидаете получить ошибку 403 или «Отказ в авторизации». Но вы получили 500, что является ошибкой приложения.
Несмотря на это, может быть, клиентское приложение может что-то сделать, чтобы не запутать сервер.
Я посмотрел заголовки исходящих HTTP-запросов, используя Fiddler . Для запроса, сгенерированного IE, заголовки выглядят так:
GET https://www.ibm.com/developerworks/mydeveloperworks/blogs/roller-ui/rendering/feed/gradybooch/entries/rss?lang=en HTTP/1.1
Accept: image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-silverlight, application/x-shockwave-flash, application/x-silverlight-2-b2, */*
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; .NET CLR 3.5.30729;)
Accept-Encoding: gzip, deflate
Host: www.ibm.com
Connection: Keep-Alive
Cookie: UnicaNIODID=Ww06gyvyPpZ-WPl6K7y; conxnsCookie=en; IBMPOLLCOOKIE=""; UnicaNIODID=QridYHCNf7M-WYM8Usr
Для запроса из XmlReader.Create (url) заголовки выглядят так:
GET https://www.ibm.com/developerworks/mydeveloperworks/blogs/roller-ui/rendering/feed/gradybooch/entries/rss?lang=en HTTP/1.1
Host: www.ibm.com
Connection: Keep-Alive
Совершенно иная разница. Кроме того, в ответ на последний я получил заголовок Set-Cookie
в ответе 500, которого не было в ответе IE.
Исходя из этого, я предположил, что именно разница в заголовках запросов, в частности в файлах cookie, сбивает с толку ibm.com.
Я не знаю, как убедить XmlReader.Create () встроить все нужные мне заголовки запроса, включая cookie. Но я знаю, как это сделать с помощью HttpWebRequest. Так что я использовал это.
Было несколько препятствий, которые мне пришлось преодолеть.
Мне нужен постоянный файл cookie для ibm.com. Для этого мне пришлось прибегнуть к p / invoke Win32 InternetGetCookie . Чтобы узнать, как это сделать, см. Класс PersistentCookies, прикрепленный к пользовательскому контенту внизу страницы документа для WebRequest . После прикрепления файла cookie я больше не получал 500 ошибок. Ура!
Но результирующий поток не может быть прочитан XmlReader.Create (). Это выглядело двоично для меня. Я понял, что мне нужно распаковать gzip или дефлированный контент. Для этого мне пришлось обернуть GZipStream или DeflateStream вокруг полученного потока ответов и использовать поток распаковки для XmlReader. установить свойство AutomaticDecompression для HttpWebRequest. Я мог бы избежать необходимости в этом, не включив в исходящий запрос «gzip, deflate» в заголовке Accept-Encoding
. Фактически, после установки свойства AutomaticDecompression эти заголовки неявно устанавливаются в исходящем HTTP-запросе.
Когда я это сделал, я получил реальный текст. Но некоторые из байтовых кодов были выключены. Затем мне нужно было использовать правильную кодировку текста в TextReader, как указано в HttpWebResponse.
После этого я получил разумную строку, но результирующий распакованный поток rss вызвал удушение XmlReader с
ReadElementString method can only be called on elements with simple or empty content. Line 11, position 25.
Я посмотрел и обнаружил небольшой блок <script>
в этом месте внутри элемента <copyright>
в документе rss. Похоже, что IBM пытается заставить браузер «локализовать» дату авторского права, добавив логику, которая запускается в браузере для форматирования даты. Для меня это выглядит излишним, или даже ошибкой со стороны IBM. Но поскольку угловая скобка внутри текстового узла элемента беспокоит XmlReader, я удалил блок скрипта с заменой Regex.
После устранения этих препятствий все заработало. Приложение .NET смогло прочитать поток RSS с этого URL https.
Дальнейшего тестирования я не проводил - чтобы увидеть, изменит ли поведение заголовок Accept
или Accept-Encoding
. Это вам нужно выяснить, если вам все равно.
Полученный код приведен ниже. Это намного хуже, чем ваш простой 3-х линейный. Я не знаю, как это сделать проще.
public void Run()
{
string url;
url = "https://www.ibm.com/developerworks/mydeveloperworks/blogs/roller-ui/rendering/feed/gradybooch/entries/rss?lang=en";
HttpWebRequest hwr = (HttpWebRequest) WebRequest.Create(url);
// attach persistent cookies
hwr.CookieContainer =
PersistentCookies.GetCookieContainerForUrl(url);
hwr.Accept = "text/xml, */*";
hwr.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-us");
hwr.UserAgent = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; .NET CLR 3.5.30729;)";
hwr.KeepAlive = true;
hwr.AutomaticDecompression = DecompressionMethods.Deflate |
DecompressionMethods.GZip;
using (var resp = (HttpWebResponse) hwr.GetResponse())
{
using(Stream s = resp.GetResponseStream())
{
string cs = String.IsNullOrEmpty(resp.CharacterSet) ? "UTF-8" : resp.CharacterSet;
Encoding e = Encoding.GetEncoding(cs);
using (StreamReader sr = new StreamReader(s, e))
{
var allXml = sr.ReadToEnd();
// remove any script blocks - they confuse XmlReader
allXml = Regex.Replace( allXml,
"(.*)<script type='text/javascript'>.+?</script>(.*)",
"$1$2",
RegexOptions.Singleline);
using (XmlReader xmlr = XmlReader.Create(new StringReader(allXml)))
{
var items = from item in SyndicationFeed.Load(xmlr).Items
select item;
}
}
}
}
}