返回> 网站首页
[转载]HttpWebRequest 二三事
yoours2011-08-22 20:28:40
简介一边听听音乐,一边写写文章。
随着REST风格的流行,直接通过 HttpWebRequest 进行服务调用的客户端应用越来越多。这里总结一些可能需要费时调查的经验,希望能帮助大家。
1. 用完的HttpWebRequest要Abort()或者要把 Response.Close()
否则会导致请求Timeout。 (HttpWebRequest.Method默认是GET)
- static void Main(string[] args)
- {
- for (int i = 0; i < 10; i++)
- {
- Console.Write("[{0}] Request - ", i + 1);
- TryGet("https://login.live.com/");
- }
- Console.Read();
- }
- static void TryGet(object obj)
- {
- try
- {
- HttpWebRequest webReq = null;
- string url = (string)obj;
- webReq = (HttpWebRequest)HttpWebRequest.Create(url);
- webReq.Timeout = 20 * 1000;
- var resp = webReq.GetResponse() as HttpWebResponse;
- resp.Close();
- Console.WriteLine("Get Response StatusCode: {0}({1})",
- resp.StatusCode, (int)resp.StatusCode);
- }
- catch (WebException we)
- {
- Console.WriteLine("Get Response StatusCode: {0}({1})",
- we.Status, (int)we.Status);
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
- }
上面的代码,会从第3次Request开始出现Timeout,因为GetResponse 后 Stream打开未关闭。
解决方法:上面的代码中加上 resp.Close(); 或者 webReq.Abort(); 就能解决。
2. 多线程中调用 HttpWebRequest 时,需要设置 ServicePointManager.DefaultConnectionLimit 数(默认连接数是 2)。
当多线程请求时,同时的连接数超过Limit时,GetResponse会抛出 Timeout WebException。
- // 用多线程同时发出4个请求
- WaitCallback methodTarget = new WaitCallback(TryGet);
- ThreadPool.QueueUserWorkItem(methodTarget, "https://login.live.com/");
- ThreadPool.QueueUserWorkItem(methodTarget, "https://login.live.com/");
- ThreadPool.QueueUserWorkItem(methodTarget, "https://login.live.com/");
- ThreadPool.QueueUserWorkItem(methodTarget, "https://login.live.com/");
解决方法:在GetResponse()之前设置 ServicePointManager.DefaultConnectionLimit = 100;
3. 当请求一个基于SSL的服务时,默认的验证行为都在 ServicePointManager 定义:
ServicePointManager.CheckCertificateRevocationList = true;
如果请求的服务端证书没有第三方的认证支持,则请求会失败,如果要完全信任服务端证书,则可以将
CheckCertificateRevocationList 设为 false。
4. 可以在 <system.net> 配置节中配置 HttpWebRequest 的属性,包括 WebProxy
- <system.net>
- <connectionManagement>
- </connectionManagement>
- <defaultProxy>
- <proxy proxyaddress="http://xxx.xxx.xxx.xxx:xxx" bypassonlocal="False"/>
- </defaultProxy>
- <settings>
- <httpWebRequest useUnsafeHeaderParsing="true"/>
- <servicePointManager checkCertificateName="true"
- checkCertificateRevocationList="true"
- enableDnsRoundRobin="true"
- expect100Continue="true"
- useNagleAlgorithm="true"/>
- </settings>
- </system.net>