2010-05-11 3 views
3

По какой-либо причине IBM использует https (не требуя учетных данных) для своих RSS-каналов. Я пытаюсь использовать https://www.ibm.com/developerworks/mydeveloperworks/blogs/roller-ui/rendering/feed/gradybooch/entries/rss?lang=en с .NET 4 SyndicationFeed. Я могу открыть этот канал в браузере, и он загружается просто отлично. Вот код:Как читать безопасный rss-канал в SyndicationFeed без предоставления учетных данных?

 using (XmlReader xml = XmlReader.Create("https://www.ibm.com/developerworks/mydeveloperworks/blogs/roller-ui/rendering/feed/gradybooch/entries/rss?lang=en")) 
     { 
      var items = from item in SyndicationFeed.Load(xml).Items 
         select item; 
     } 

Вот исключение:

System.Net.WebException was unhandled by user code 
Message=The remote server returned an error: (500) Internal Server Error. 
Source=System 
StackTrace: 
    at System.Net.HttpWebRequest.GetResponse() 
    at System.Xml.XmlDownloadManager.GetNonFileStream(Uri uri, ICredentials credentials, IWebProxy proxy, RequestCachePolicy cachePolicy) 
    at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials, IWebProxy proxy, RequestCachePolicy cachePolicy) 
    at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn) 
    at System.Xml.XmlReaderSettings.CreateReader(String inputUri, XmlParserContext inputContext) 
    at System.Xml.XmlReader.Create(String inputUri, XmlReaderSettings settings, XmlParserContext inputContext) 
    at System.Xml.XmlReader.Create(String inputUri) 
    at EDN.Util.Test.FeedAggTest.LoadFeedInfoTest() in D:\cdn\trunk\CDN\Dev\Shared\net\EDN.Util\EDN.Util.Test\FeedAggTest.cs:line 126 

Как настроить читателя на работу с подачей по протоколу HTTPS?

+1

Что такое ошибка сервера? – David

+0

@David, я добавил информацию об ошибке на свое сообщение –

+0

Код, который вы опубликовали, не содержит обращения к WebClient.OpenRead. Можете ли вы показать нам код, создающий исключение? – dtb

ответ

9

Я не думаю, что это имеет какое-либо отношение к безопасности. Ошибка 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(), чтобы вставлять все заголовки запросов, которые я хотел, включая печенье. Но я знаю, как это сделать с помощью HttpWebRequest. Поэтому я использовал это.

Было несколько препятствий, которые я должен был очистить.

  1. Мне нужен постоянный файл cookie для ibm.com. Для этого мне пришлось прибегнуть к p/invoke из Win32 InternetGetCookie. См. Класс PersistentCookies, прикрепленный в содержимом, предоставленном пользователями, в нижней части страницы документа для WebRequest, как это сделать. После прикрепления файла cookie я больше не получал 500 ошибок. Ура!

  2. Но полученный поток не может быть прочитан XmlReader.Create(). Мне это показалось двоичным. Я понял, что мне нужно сжать gzip или сдутый контент. Для этого мне пришлось обернуть GZipStream или DeflateStream вокруг полученного потока ответов и использовать поток распаковки для XmlReader. задать объект AutomaticDecompression собственности на HttpWebRequest. Я мог бы избежать необходимости в этом, не включая «gzip, deflate» в заголовке Accept-Encoding в исходящем запросе. Фактически, после установки свойства AutomaticDecompression эти заголовки задаются неявно в исходящем HTTP-запросе.

  3. Когда я это сделал, я получил фактический текст. Но некоторые из байтовых кодов были отключены.Затем мне нужно было использовать правильную текстовую кодировку в TextReader, как указано в HttpWebResponse.

  4. После этого, я получил толковую строку, но в результате распакованного поток 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 с этого https-url.

Я не проводил никаких дальнейших испытаний - чтобы увидеть, будет ли изменяться заголовок 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; 
       } 
      } 
     } 
    } 
} 
+0

Какое фантастическое усилие! Я ценю ваше время на этом. Я подозревал обе эти проблемы: cookie и значения заголовков, но я надеялся, что сначала это будет просто решить. Не знаю почему IBM хочет сделать свои требования к потреблению кормов настолько тяжелыми. Я обрабатываю около 150 различных URL-адресов каналов, и никто другой не делает этого таким образом. Я посмотрю, смогу ли я сделать общее решение из ваших прекрасных усилий. Огромное спасибо. –

+0

Я смог воспроизвести ваш успешный тест. Еще раз спасибо. Теперь, чтобы узнать, работает ли это для остальных кормов, я должен потреблять ... –

 Смежные вопросы

  • Нет связанных вопросов^_^