我不认为它与安全性有关。 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来做到这一点。所以我用了。
我不得不清除几个障碍。
我需要ibm.com的永久性cookie。为此,我不得不诉诸Win32 InternetGetCookie的p/invoke。请参阅0123ns文档页底部的用户贡献内容中附加的PersistentCookies类,了解如何执行此操作。附上cookie后,我不再收到500个错误。万岁!
但是生成的流无法被XmlReader.Create()读取。它看起来是二元的。我意识到我需要解压缩gzip或泄漏的内容。为此,我必须
在收到的响应流周围包装GZipStream或DeflateStream,并为XmlReader使用解压缩流。
在HttpWebRequest上设置AutomaticDecompression属性。我可以通过在出站请求中的Accept-Encoding
标头中不包括“gzip,deflate”来避免这种需要。实际上,在设置AutomaticDecompression属性之后,这些标头将隐式设置在出站HTTP请求中。
当我这样做,我得到了实际的文字。但是一些字节码已关闭。接下来,我需要在TextReader中使用正确的文本编码,如HttpWebResponse中所示。
这样做后,我得到了一个明智的字符串,但由此产生的解压缩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;
}
}
}
}
}
什么是服务器错误? – David 2010-05-11 19:55:18
@David,我将错误信息添加到我的文章 – 2010-05-11 20:06:14
您发布的代码不包含对WebClient.OpenRead的调用。你能告诉我们产生异常的代码吗? – dtb 2010-05-11 20:50:06