C# 采用HttpWebRequest 、WebClient和HttpClient下载https的文件异常问题
今天有个客户反应,程序下载文件失败,无法正常使用。
远程客户电脑后,查看错误日志,都是提示https:****************************.dll等一系列文件的下载错误提示
提示基础连接已经关闭: 发送时发生错误。
在网上找了很多方案都没有能解决,大多都是https链接时增加指定协议,很遗憾未能解决
HttpWebRequest request; HttpWebResponse response; request = (HttpWebRequest)WebRequest.Create(strUrl); if (isHttps) { ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); request.ProtocolVersion = HttpVersion.Version10; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; }
找不到原因,客户又着急使用,就想着换成WebClient下载类试试,于是写了个粗糙的demo
WebClient webClient = new WebClient(); webClient.DownloadFile(textBox1.Text, Path.GetFileName(textBox1.Text));
发现还是提示同样的错误,这个时候一头雾水,心里万马奔腾
心思不能乱,不行我在换,72般武艺都耍上,于是用HttpClient类,写个demo试试
using (HttpClient client = new HttpClient()) { // 使用异步方法下载文件 HttpResponseMessage response = await client.GetAsync(textBox1.Text); response.EnsureSuccessStatusCode(); // 确保请求成功 // 保存文件 using (FileStream fileStream = File.Create( Path.GetFileName(textBox1.Text))) { await response.Content.CopyToAsync(fileStream); } }
发现还是不能下载文件,但是错误提示有变化,提示为“因为算法不同,客户端与服务器无法通信”
于是寻找这个错误的解决方案,需要在注册表这个位置将协议值修改下
计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
一看客户电脑上,好几个,一个个修改太麻烦,直接将协议改名,让这个设置失效。
在启动测试程序下载文件,发现正常了,完工。
后来在网上又发现一个解决方案,感觉可能能行,由于客户问题处理完后,无法在霸占其电脑了,将这个方案记录下,后续遇到在验证,或者有遇到相同问题的天涯沦落人验证后给我留言,谢谢
在工作中要获取一个网络api下的内容,因为要auth认证,本以为很简单
string url="https://....."; string usernamePassword = CustomerID + ":" + CustomerCertificate; string basic = Convert.ToBase64String(new ASCIIEncoding().GetBytes(usernamePassword)); HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url); myReq.Headers.Add("Authorization", "Basic " + basic); HttpWebResponse myRes = (HttpWebResponse)myReq.GetResponse(); //<-- 这里就报错了 Stream resStream = myRes.GetResponseStream(); StreamReader strReader = new StreamReader(resStream); string resStr = strReader.ReadToEnd(); Console.WriteLine(resStr);
结果运行时提示“提示基础连接已经关闭: 发送时发生错误。”
在浏览器下访问网址则正常,刚开始怀疑是basic不对,在浏览器下用同样的值模拟了一下能正常获取,然后把https换成http程序又能正常获取了,定位到问题出在ssl证书上
查了一下资料
添加以下代码
ServicePointManager.Expect100Continue = true; ServicePointManager.CheckCertificateRevocationList = true; ServicePointManager.DefaultConnectionLimit = 100; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
改回https还是提示原来的异常,换了另外一个https的网址测试却又正常,在浏览器下对比两个https网址的ssl证书,发现能正常访问的测试网址是tls1.0 不能访问的网址是tls1.2
找到问题了,原来在.net4.5以下tls1.2的设置如下
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; //.net4.5及以上 //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
再次运行,ok