我认为这与安全没有任何关系。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来实现这一点。所以我用了。
我不得不跨过几道障碍。
-
我需要ibm.com的持久cookie。为此,我不得不求助于对Win32的P/Invoke
InternetGetCookie
. 参见文档页面底部用户贡献内容中附加的PersistentCookies类
WebRequest
关于如何做到这一点。在附加cookie之后,我不再得到500个错误。万岁!
-
但xmlReader.create()无法读取结果流。在我看来,它是二元的。我意识到我需要去压缩gzip或泄气的内容。为此我不得不
围绕接收到的响应流包装gzipstream或deflatestream,并使用用于xmlReader的解压缩流。
设置
AutomaticDecompression
HttpWebRequest上的属性。我本来可以避免这种需要,不包括“gzip,deflate”在
Accept-Encoding
出站请求中的头。实际上,在设置automaticdecompression属性之后,这些头在出站HTTP请求中被隐式设置。
-
当我这样做的时候,我得到了真实的文本。但有些字节码是关闭的。接下来,我需要在文本阅读器中使用正确的文本编码,如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的一个bug。但由于元素文本节点内的尖括号干扰了xmlReader,所以我用regex替换移除了脚本块。
在克服了这些障碍之后,它成功了。.NET应用程序能够从该https URL读取RSS流。
我没有做任何进一步的测试-看看是否改变
Accept
报头或
接受编码
头会改变行为。如果你愿意的话,那就由你来决定。
结果代码如下。它比你简单的三行式要丑得多。我不知道怎么让它简单一点。
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;
}
}
}
}
}