2010-05-11 58 views
3

无论出于何种原因,IBM使用https(无需凭据)来提供RSS源。我试图在.NET 4 SyndicationFeed上使用https://www.ibm.com/developerworks/mydeveloperworks/blogs/roller-ui/rendering/feed/gradybooch/entries/rss?lang=en。我可以在浏览器中打开此提要,并且加载得很好。下面的代码:如何在不提供凭据的情况下将安全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 2010-05-11 19:55:18

+0

@David,我将错误信息添加到我的文章 – 2010-05-11 20:06:14

+0

您发布的代码不包含对WebClient.OpenRead的调用。你能告诉我们产生异常的代码吗? – dtb 2010-05-11 20:50:06

回答

9

我不认为它与安全性有关。 500错误是服务器端错误。 XmlReader.Create(url)生成的请求中的某些内容混淆了ibm网站。如果这仅仅是一个安全问题,正如您的问题所建议的那样,那么您会期望得到一个403错误,或者“授权被拒绝”。但是你有500,这是一个应用程序错误。

即便如此,也许有客户端应用程序可以做的事情,以避免混淆服务器。

我使用Fiddler查看了传出的HTTP请求标题。对于由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. 我需要ibm.com的永久性cookie。为此,我不得不诉诸Win32 InternetGetCookie的p/invoke。请参阅0123ns文档页底部的用户贡献内容中附加的PersistentCookies类,了解如何执行此操作。附上cookie后,我不再收到500个错误。万岁!

  2. 但是生成的流无法被XmlReader.Create()读取。它看起来是二元的。我意识到我需要解压缩gzip或泄漏的内容。为此,我必须 在收到的响应流周围包装GZipStream或DeflateStream,并为XmlReader使用解压缩流。 在HttpWebRequest上设置AutomaticDecompression属性。我可以通过在出站请求中的Accept-Encoding标头中不包括“gzip,deflate”来避免这种需要。实际上,在设置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>块,在该位置,在rss文档中的<copyright>元素内。看起来IBM正试图让浏览器通过附加在浏览器中运行的逻辑来“格式化”日期来“定位”版权日期。似乎对我来说过分夸张,甚至是IBM的一个错误。但是因为元素的文本节点中的尖括号困扰了XmlReader,所以我使用Regex替换删除了脚本块。


清除这些障碍后,它的工作。 .NET应用程序能够从该https网址读取RSS流。

我没有做任何进一步的测试 - 看看是否改变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个不同的供稿网址,没有其他人这样做。我会看看我能否通过您的出色努力来制定一个通用的解决方案。非常感谢。 – 2010-05-12 03:52:59

+0

我能够重现您的成功测试。再次感谢。现在看看它是否适用于我必须消费的其他Feed – 2010-05-12 04:08:55

相关问题