最关键的问题是它在处理 Cookies 上有些混乱,而 Cookies 是你访问那些需要认证网页的关键。
总结一下 Httpwebrequest 编程中主要的问题:
Cookies 问题(重中之中); 浏览器版本问题; Http 头的问题,其中需要注意 post 的 content-type 和 Http 头中是否被加入了不标准的内容(这个问题太隐蔽);返回的 html 数据和浏览器对应的页面 html 不一致; 提交数据的编码问题,编码问题很讨厌。由于编码采用了错误方式,我的 msn space 被封了几个小时; Hidden 问题,有些服务器会写一个 hidden 到页面,这个Hidden也需要提交回去。最后友情赠送方法二个:
获取一个时间值,很多网站使用了这个时间值,对应于 javascript 中的 gettime 方法; MD5加密;
程序代码 程序代码public static string GetMilliseconds() { double d = DateTime.Now.Subtract(new DateTime(1970, 1, 1, 8, 0, 0)).TotalMilliseconds; return Convert.ToInt64(d).ToString();}public static string GetMD5(string str) { MD5 md5 = new MD5CryptoServiceProvider(); return BitConverter.ToString(md5.ComputeHash(UTF8Encoding.Default.GetBytes(str))).ToLower().Replace("-", "");}HttpWebRequest 编程相关问题 (7)在上一节说了由于跳转产生的返回 htm 数据不是预定数据的问题。这一节继续来说这个问题
Request 对象有个 UserAgent,让你标识浏览器版本,大部分的时候你可以随便写这个参数。
但是,有些网站是对浏览器是有要求的,并且完成了对应优化的。
比如 MSN Space:如果你的浏览器版本不对,那么服务器返回的数据也不一样。
甚至有的时候在有些网站还利用 javascript 写 cookies 到浏览器客户端。这个浏览器客户端再传回 cookies 到服务器。
而 Httpwebrequest 在这一点上就非常无力。因为它只是一个解析 http 协议的 class,而不是解析和运行网页的 class
唯一的办法就是你模拟 Cookie,但你的模拟代价太大
由于这些问题(版本,cookies 等等)的影响,你从 IE(firefox) 浏览器获取到的 html 数据和 httpwebrequest 获取到的数据相差很多。
因而,当你在依据浏览器获取到的 html 制定解析模版分析 httpwebrequest 的数据时,你会发觉无论怎么样都找不到数据。
第二个要说的是,我所述的内容都是在 .net 2.0 基础上。
昨天有个朋友问了一个问题,说他获取到的数据是乱码,无论那种解码都是无效。
虽然发现问题的原因是 html 数据被压缩,但我这边 httpwebrequest 自动完成了解压缩的,因此没有解决问题。
后来查看某个 msdn 发现某个解压缩属性是出现在 .net 2.0 里面的,所以推断是 .net 的版本问题,一问果然是 vb.net 2003。
然后今天他告诉我:解决了,版本问题。
因此提醒使用 .net 2.0
HttpWebRequest 编程相关问题 (6)HttpWebRequest 编程过程中属性 AllowAutoRedirect 一定要设置为 true,除非有特别的捕获要求。
这个属性是让 WebRequest 自动完成跳转功能。
但是有个非常奇怪的问题,这种跳转有的时候是很奇特的。
简单来讲:
访问 page1.aspx; 跳转到 page2.aspx; 再跳转到 page3.aspx;在 httpwebrequest 中这种跳转可能完成,而且执行结束了,但是你通过 httpwebresponse 返回的 html 却可能不是 page3.aspx 的数据,而这时如果你要判断某个页面执行成功的方法就要想比较特殊的方法了。
要么主动控制异常的校验,要么看看对应的 cookies 的值是否获取到。
一般情况下,使用 cookies 判断最好,因为这种页面之间的跳转都是有 cookies 的产生的。
比如我在模拟 msn space 的登陆时,在 httpwebrequest 正常跳转完成后有 12 个 cookies,而 httpwebresponse 返回的页面数据和我通过浏览器真实访问的数据却不一致,但是我的登陆完成,跳转完成。这时我必须人工告诉程序你执行 OK 了。
关于这点,当你遇到就会明白了。HttpWebRequest 编程相关问题 (5)之前的段落有下面一段代码:
程序代码 程序代码string en = oresponse.CharacterSet;if (en == null||en.Length==0) en = "gb2312";if (en.ToLower() == "iso-8859-1") en = "gb2312";StreamReader reader = new StreamReader(dataStream, Encoding.GetEncoding(en));
其实是判断 Response 返回的数据是什么编码格式:GBK, UTF-8, Unicode, iso-8858-1?
如果不能获取到编码格式,那么我们在解码时也是错误的。
这点还是同 http 协议有关,也可以说是同 web 容器本身的输出有关,在这个基础上还有一个点值得提一下:
Content-Encoding: gzipTransfer-Encoding: chunked
这也是同压缩解码有关,虽然同上面的说的不是一回事。
写本文的另外一点的主要方面是之前的代码有这样一句话:
orequest.UserAgent = "NutsSoft.com.cn";告诉服务器浏览器的软件版本。
大部分的服务器不会检查这个东西,但是总是有 BT 存在的。比如微软
MSN的网站是检查了浏览器的版本的。好像是根据版本来判断浏览器是否支持 javascript
所以上面的一句话只能改成了
orequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0;NutsSoft.com.cn)";而这个小小的问题又困扰了我大半天。其实之前也遇到同样的问题,只是这次没有预料到会发生而已。HttpWebRequest 编程相关问题 (4)第一个问题还是同 Cookies 相关,同 Cookies 的存储有很多关系,以 为例,可能存在下面两个 Cookies
1,Domain=".writeblog.csdn.net";
2,Domain="writeblog.csdn.net";
值得注意的是这是两个不同的 Domain。但是如果两个 Cookie 的 Name 一样的话如何办?
当然浏览器有自己的办法,我们不去深究,但是我们用 HttpWebRequest 提交 Cookies 上去的时候怎么办?
Cookie 名称相同,Domain 不同,我们提交那个呢?
呵呵,其实俺也不知道,只是俺的解决办法是有的,我这里使用起来没有问题,但是不保证换个地方不出错。
待会写出代码来。
第二个问题也是害死人。我今天一天又耗费了无数的脑细胞啊!!!!
有的网站使用了 ajax 技术。我们捕获到的 HttpHeader 如下:
程序代码 程序代码POST /control/doPostDiary.b HTTP/1.1Accept: */*Accept-Language: zh-cnReferer: http://xxxx.xxx.com/control/diary/postDiary.bContent-Type: text/xml;charset=GBKUA-CPU: x86Accept-Encoding: gzip, deflateUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2; WOW64; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)Host: dragonya.bokee.comContent-Length: 1621Connection: Keep-AliveCache-Control: no-cacheCookie: xxxx
<这里是个 xml 字符串>
当用 httpwebrequest 模拟这个请求时,俺再次花了无数的脑细胞都没有办法解决。
我一直以为我在模拟浏览器请求的时候是不是少传递了 Cookie?
还是 jspsessionid 又在不停的变化???找了无数的原因和方式
反正一个下午没有解决,一直到晚上不甘心才发觉问题所在:
Post 方式传递数据是 Content-Type=application/x-www-form-urlencoded
而那个 ajax 提交数据时 Content-Type: text/xml;charset=GBK
这是一个小小的,根本想不到的问题,对于 post 方式,我们的思维已经固化了“application/x-www-form-urlencoded”,想不到也不知道有这种情况。
为什么是我在摸着石头过河啊?为什么没有别人摸着石头过了河,然后弄一座桥呢???
最新的代码如下:
程序代码 程序代码public struct SendHead { public string Host; public string Referer; public CookieCollection Cookies; public string Action; public string PostData; public string Method; public string ContentType; public string Html;}public class Http { public CookieCollection Cookies = null;
public string Send(ref SendHead oHead) { HttpWebResponse oresponse = null; HttpWebRequest orequest = (HttpWebRequest)HttpWebRequest.Create(oHead.Host + oHead.Action); orequest.ProtocolVersion = new Version("1.1"); orequest.Referer = oHead.Referer; orequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, */*"; orequest.CookieContainer = new CookieContainer(); orequest.Timeout = 30000; if (oHead.Cookies != null) { string cookiesValue = ""; foreach (Cookie o in oHead.Cookies) { cookiesValue += o.Name + "=" + o.Value + ","; } orequest.CookieContainer.SetCookies(new Uri(oHead.Host), cookiesValue); } //oRequest.CookieContainer.SetCookies(oRequest.RequestUri,cookies[]. orequest.UserAgent = "NutsSoft.com.cn"; orequest.Credentials = CredentialCache.DefaultCredentials;
//设置POST数据 if (oHead.Method.ToLower() == "post") { orequest.Method = "POST"; byte[] byteData = ASCIIEncoding.ASCII.GetBytes(oHead.PostData); if (string.IsNullOrEmpty(oHead.ContentType)) { orequest.ContentType = "application/x-www-form-urlencoded"; } else { orequest.ContentType = oHead.ContentType; } orequest.ContentLength = byteData.Length; Stream WriteStream = orequest.GetRequestStream(); WriteStream.Write(byteData, 0, byteData.Length); WriteStream.Close(); } try { oresponse = (HttpWebResponse)oRequest.GetResponse(); } catch (WebException ex) { if (ex.Response != null) { oresponse = (HttpWebResponse)ex.Response; } else { throw ex; } } //oResponse.Cookies.Add(oRequest.CookieContainer.GetCookies(oRequest.RequestUri)); CookieCollection tmpCookies = orequest.CookieContainer.GetCookies(oRequest.RequestUri); foreach (Cookie o in tmpCookies) { if (oResponse.Cookies[o.Name] != null) { // oresponse.Cookies[o.Name].Value = o.Value; } else { oresponse.Cookies.Add(o); }
} Stream dataStream = oresponse.GetResponseStream();
string en = oresponse.CharacterSet; if (en == null) en = "gb2312"; if (en.ToLower() == "iso-8859-1") en = "gb2312"; StreamReader reader = new StreamReader(dataStream, Encoding.GetEncoding(en)); string responseFromServer = reader.ReadToEnd(); Cookies = oresponse.Cookies; oHead.Cookies = oresponse.Cookies; reader.Close(); dataStream.Close(); oresponse.Close(); return oHead.Html = responseFromServer; }}
如果你打算使用上面的代码,或者认为有帮助的话,江湖规矩:回一帖三!!!HttpWebRequest 编程相关问题 (3)在 "HttpWebRequest编程相关问题(2)" 中为了获取到 500 错误时对于 GetResponse 使用了 try catch 方法,代码如下:
程序代码 程序代码try { oresponse = (HttpWebResponse)oRequest.GetResponse();} catch (WebException ex) { oresponse = (HttpWebResponse)ex.Response;}
但是这种异常处理还是有遗漏,就是当 httpwebrequest 访问某个网站时,对方网站长时间没有响应或者 timeout,
这种 timeout 产生时,上面代码中的 orequest.GetResponse() 返回的对象是 NULL
所以还需要进一步调整为:
程序代码 程序代码try { oresponse = (HttpWebResponse)oRequest.GetResponse();} catch (WebException ex) { if (ex.Response != null) { oresponse = (HttpWebResponse)ex.Response; } else { throw ex; }}
虽然不是什么大问题,但是遇到了就比较讨厌。
另,为了主动 timeout,还需要对于 request 对象设置 timeout 的数值HttpWebRequest 编程相关问题 (2)在使用 HttpWebRequest 访问需要登陆的页面时必然会涉及到 Cookies,但是 HttpWebRequest 对象和相关方法在设计时还是存在一些问题
比如:
访问页面 A,得到 Cookie o1 包含jspsessionid;把 o1 给 HttpWebRequest 然后登陆页面 B,得到一个新的Cookies o2,里面包含了很多相关信息;把 o2 给 HttpWebRequest 然后登陆页面 C。一般情况下你会使用如下代码:
程序代码 程序代码HttpWebRequest orequest = (HttpWebRequest)HttpWebRequest.Create(oHead.Host+ oHead.Action); orequest.ProtocolVersion = new Version("1.1");orequest.Referer = oHead.Referer;orequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, */*";orequest.CookieContainer = new CookieContainer();orequest.CookieContainer .Add(o2)orequest.UserAgent = "blogmove.cn";orequest.Credentials = CredentialCache.DefaultCredentials;
上面的 orequest.CookieContainer.Add(o2) 基本上没有错,而且按照道理来说也不会有错
但是事实上 Micosoft 在设计这一部分是存在缺陷的,或者“Microsoft 有独立的定位”,也许还有我不知道的地方
上文的代码一般情况下不会有错,Cookies 值会被正常传递给服务器,但是如果 o2 的内容是下面的内容的话,上面的代码就可能会存在缺陷:
程序代码 程序代码Set-Cookie: JSESSIONID=555287820C8B46311649EF947F77DF12; Path=/controlSet-Cookie: Code=b4874b74; Domain=blogmove.cn; Path=/Set-Cookie: mc=1,platform,0; Domain=blogmove.cn; Path=/
(注意这里是 HttpHeader 方式)
上面的这段 Head 假设是在访问 http://file.blogmove.cn/t1.aspx 时,服务器写给浏览器的。
o2 被传递给 orequest,oRequest 访问 http://file.blogmove.cn/test.aspx 时,上面三个 cookie,只有第一个被 orequest 传递给了服务器,服务器收不到后面两个 cookies,Test.aspx 页面就会返回错误的结果。
原因就是 Cookie 是有 Domain 的,
第一个 Cookie 的 Domain 是默认 http://file.blogmove.cn;
第二和三个 Cookie 的 Domain 是 blogmove.cn;
orequest 在上行 Cookie 时只上行了当前 Domain=http://file.blogmove.cn 的 Cookie,而放弃了 Domin=blogmove.cn 的 Cookie,oRequest 分辨了Uri;
这种行为和我们正常预想的不符,因为我们平常是按照浏览器的行为在思考:应该上行所有 blogmove.cn 下的所有 Cookies.
按照道理来说,我认为 Request 对象应该自动分辨和解析 Cookies 里面的 domain.
因此为了保证 orequest 能够达到我们的目的,所以应该修改上面的 C# 代码如下:
程序代码 程序代码public string Send(ref SendHead oHead) { HttpWebResponse oresponse = null; HttpWebRequest orequest = (HttpWebRequest)HttpWebRequest.Create(oHead.Host + oHead.Action); orequest.ProtocolVersion = new Version("1.1"); orequest.Referer = oHead.Referer; orequest.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, */*"; orequest.CookieContainer = new CookieContainer(); if (oHead.Cookies != null) { string cookiesValue = ""; foreach (Cookie o in oHead.Cookies) { cookiesValue += o.Name + "=" + o.Value + ","; } orequest.CookieContainer.SetCookies(new Uri(oHead.Host), cookiesValue); } //oRequest.CookieContainer.SetCookies(oRequest.RequestUri,cookies[]. orequest.UserAgent = "NutsSoft.com.cn"; orequest.Credentials = CredentialCache.DefaultCredentials;
//设置POST数据 if (oHead.Method.ToLower() == "post") { orequest.Method = "POST"; byte[] byteData = ASCIIEncoding.ASCII.GetBytes(oHead.PostData); orequest.ContentType = "application/x-www-form-urlencoded"; orequest.ContentLength = byteData.Length; Stream WriteStream = orequest.GetRequestStream(); WriteStream.Write(byteData, 0, byteData.Length); WriteStream.Close(); } try { oresponse = (HttpWebResponse)oRequest.GetResponse(); } catch (WebException ex) { oresponse = (HttpWebResponse)ex.Response; } oresponse.Cookies = orequest.CookieContainer.GetCookies(oRequest.RequestUri); Stream dataStream = oresponse.GetResponseStream();
string en = oresponse.CharacterSet; if (en == null) en = "gb2312"; if (en.ToLower() == "iso-8859-1") en = "gb2312"; StreamReader reader = new StreamReader(dataStream, Encoding.GetEncoding(en)); string responseFromServer = reader.ReadToEnd(); Cookies = orequest.CookieContainer.GetCookies(oRequest.RequestUri); oHead.Cookies = orequest.CookieContainer.GetCookies(oRequest.RequestUri); reader.Close(); dataStream.Close(); oresponse.Close(); return oHead.Html = responseFromServer;}
转载于:https://www.cnblogs.com/yidanda/archive/2009/09/13/1565690.html
相关资源:DirectX修复工具V4.0增强版