前几天在做一个使用URL通过WebRequest请求HTML页面的功能的时候遇到了点坑,程序在开发环境没有任何的问题,部署到linux mono上之后就跪了。代码如下:

public static string GetHTML(string url)
{
string htmlCode;
try
{
HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
webRequest.Timeout = 30000;
webRequest.Method = "GET";
webRequest.UserAgent = "Mozilla/4.0";
webRequest.Headers.Add("Accept-Encoding", "gzip, deflate"); HttpWebResponse webResponse = (System.Net.HttpWebResponse)webRequest.GetResponse();
//获取目标网站的编码格式
string contentype = webResponse.Headers["Content-Type"];
Regex regex = new Regex("charset\\s*=\\s*[\\W]?\\s*([\\w-]+)", RegexOptions.IgnoreCase);
if (webResponse.ContentEncoding.ToLower() == "gzip")//如果使用了GZip则先解压
{
using (System.IO.Stream streamReceive = webResponse.GetResponseStream())
{
using (var zipStream = new System.IO.Compression.GZipStream(streamReceive,
System.IO.Compression.CompressionMode.Decompress))
{
//匹配编码格式
if (regex.IsMatch(contentype))
{
Encoding ending = Encoding.GetEncoding(regex.Match(contentype).Groups[1].Value.Trim());
using (StreamReader sr = new System.IO.StreamReader(zipStream, ending))
{
htmlCode = sr.ReadToEnd();
}
}
else
{
using (StreamReader sr =
new System.IO.StreamReader(zipStream, Encoding.UTF8))
{
htmlCode = sr.ReadToEnd();
}
}
}
}
}
else
{
using (System.IO.Stream streamReceive = webResponse.GetResponseStream())
{
using (System.IO.StreamReader sr = new System.IO.StreamReader(streamReceive, Encoding.Default))
{
htmlCode = sr.ReadToEnd();
}
}
}
return htmlCode; }catch(Exception ex)
{
LogHelper.WriteException("GetHTML", ex, new { Url = url });
return "";
} }

无论是HTTP还是HTTPS协议,网页HTML一样能获取得到。开发环境在Windows10 + VS2013,整个代码跑起来没什么问题。

网站部署到linux Jexus之后HTTP协议的网站同样可以获取到HTML,遇到HTTPS协议的网站的时候就跪了。

抓到的异常信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
System.Net.WebException: Error: TrustFailure (The authentication or decryption has failed.) 
---> System.IO.IOException: The authentication or decryption has failed.
---> System.IO.IOException: The authentication or decryption has failed.
---> Mono.Security.Protocol.Tls.TlsException:
Invalid certificate received from server. Error code: 0xffffffff800b0109
at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecord
(IAsyncResult asyncResult) <0x41b58d80 + 0x0013e> in <filename unknown>:0
at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord
(IAsyncResult ar, Boolean ignoreEmpty) <0x41b58cb0 + 0x00031> in <filename unknown>:0
at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker
(IAsyncResult result) <0x41b72a40 + 0x0023f> in <filename unknown>:0
--- End of inner exception stack trace ---
at Mono.Security.Protocol.Tls.SslClientStream.EndNegotiateHandshake
(IAsyncResult result) <0x41ba07e0 + 0x000f3> in <filename unknown>:0
at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback
(IAsyncResult asyncResult) <0x41ba0540 + 0x00086> in <filename unknown>:0
--- End of inner exception stack trace ---
at Mono.Security.Protocol.Tls.SslStreamBase.EndRead
(IAsyncResult asyncResult) <0x41b73fd0 + 0x00199> in <filename unknown>:0
at Mono.Net.Security.Private.LegacySslStream.EndAuthenticateAsClient
(IAsyncResult asyncResult) <0x41b73f30 + 0x00042> in <filename unknown>:0
at Mono.Net.Security.Private.LegacySslStream.AuthenticateAsClient (System.String targetHost,
System.Security.Cryptography.X509Certificates.X509CertificateCollection
clientCertificates, SslProtocols enabledSslProtocols,
Boolean checkCertificateRevocation) <0x41b6a660 + 0x00055> in <filename unknown>:0
at Mono.Net.Security.MonoTlsStream.CreateStream (System.Byte[] buffer)
<0x41b69c30 + 0x00159> in <filename unknown>:0
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
<0x41b67660 + 0x001f9> in <filename unknown>:0
at System.Net.HttpWebRequest.GetResponse () <0x41b60920 + 0x0005a> in <filename unknown>:0
at WebBookmarkUI.Commom.HTTPHelper.GetHTML (System.String url) <0x41b59b70 + 0x00235>
in <filename unknown>:0

有用的信息基本就是:

  1. Invalid certificate received from server
  2. The authentication or decryption has failed

一开始百思不得其解,为嘛好好的程序在开发环境跑得都好的,到了mono上就挂了,多疑的我还以为是mono的bug。
今天静下心来去找了一下资料,发现Mono的文档有这个问题的描述,认真读了一遍,又去请教了一番宇内流云大大,终于弄懂了是什么回事。

先贴一下相关资料:

  1. stackoverflow mono-webrequest-fails-with-https

  2. mono doc security

这个问题是出现的原因是Windows自带了HTPPS的根证书,linux默认则是没有带有根证书的。我们的mono在调用WebRequest去请求HTTPS协议的网站的时候,找不到任何有效的根证书,所以抛出上面的异常了。

解决方案也很简单,为linux导入一下HTTPS根证书就好。

在linux服务器上面执行下面这条命令。

mozroots --import --ask-remove --machine

然后在网站的Application_Start()里面添加下面代码:

1
2
3
4
5
6
7
 System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true; // **** Always accept
};

完事。

这个故事告诉我们,linux干活都是要亲力亲为呀。

原文首发于:codelover.link

mono webreques https exception的更多相关文章

  1. mono的https使用使用事项

    private static void SetCertificatePolicy() { if( ServicePointManager.ServerCertificateValidationCall ...

  2. jexus5.8.2 linux x64通用版[未集成mono] 配置https

    一.找到mono安装位置 sudo find / -name mono 二.首先查看"/lib"或"/usr/lib"等系统库文件夹中是否有SSL库文件的名字, ...

  3. jexus linux x64[标准版] - 未集成mono 配置https

    一.找到mono安装位置 sudo find / -name mono 二.首先查看“/lib”或“/usr/lib”等系统库文件夹中是否有SSL库文件的名字,该文件名应该是“libssl.so.版本 ...

  4. Java调用Http/Https接口(7,end)--WebClient调用Http/Https接口

    WebClient是Spring提供的非阻塞.响应式的Http客户端,提供同步及异步的API,将会代替RestTemplate及AsyncRestTemplate.文中所使用到的软件版本:Java 1 ...

  5. Mono提供脚本机制(C#绑定C++)

    1.下载安装最新版mono,https://www.mono-project.com/ 2.添加头文件路径C:\Program Files\Mono\include\mono-2.0,添加库路径C:\ ...

  6. VS2013中的MVC5模板部署到mono上的艰辛历程

    部署环境:CentOS7 + Mono 3.10 + Jexus 5.6 在Xamarin.Studio创建的asp.net项目,部署过程非常顺利,没有遇到什么问题:但在VS2013中创建的asp.n ...

  7. 从Unity3D编译器升级聊起Mono

    接前篇Unity 5.3.5p8 C#编译器升级,本文侧重了解一些Mono的知识. Unity3D的编译器升级 新升级的Mono C#编译器(对应Mono 4.4) Unity编辑器及播放器所使用的M ...

  8. Unity Mono脚本 加密

    加密环境 引擎版本:Unity3D 5.3.4 及更高版本 (使用Mono而并非IL2CPP) 操作系统:CentOS 6.2(Final) 加密环境:Android.IOS(暂定) 加密对象:C#源 ...

  9. MVC5模板部署到mono

    VS2013中的MVC5模板部署到mono上的艰辛历程 2014-10-27 09:30 by FuzhePan, 3954 阅读, 46 评论, 收藏, 编辑 部署环境:CentOS7 + Mono ...

随机推荐

  1. Arcgis for Android 空间数据WKT与JSON描述

    点线面数据标准格式 一. 点 WKT: POINT(-118.4 -45.2) JSON: { "x": -118.4, "y": -45.2, "s ...

  2. 【[USACO16OPEN]262144】

    发现这个数列的范围特别大但是值域的范围特别小 于是可以大胆猜测这道题值域肯定需要开到状态里去 又发现\(262144=2^{18}\)这个暗示非常明显啊,暗示这道题跟二进制有关系 其实也没什么关系 设 ...

  3. luogu P4168 [Violet]蒲公英

    嘟嘟嘟 分块经典题竟然是一道黑题…… 分块求区间众数的大体思想是对于询问区间[L, R],预处理出这中间的整块的众数,然后统计两边零散的数在[L, R]中出现的次数,最后取出现次数最多且最小的数. 因 ...

  4. 【转】彻底理解安卓里的ldpi、mdpi、hdpi、xhdpi、xxhdpi文件夹含义

    这个问题我相信困惑了好多人包括很多老鸟,而且有的人以为自己理解其实是错误的,包括之前的我在内,在做安卓适配的时候,一般让美工做720*1280的切图,就直接放到xhdpi下,如果是做了1080*192 ...

  5. 【转】总结oninput、onchange与onpropertychange事件的用法和区别

    经本人测试在chrome下的从历史记录中选取值的时候也户触发input事件 前端页面开发的很多情况下都需要实时监听文本框输入,比如腾讯微博编写140字的微博时输入框hu9i动态显示还可以输入的字数.过 ...

  6. jeesite介绍及链接

    https://github.com/thinkgem/jeesite   (需FQ) JeeSite 是一个企业信息化开发基础平台,Java企业应用开源框架,Java EE(J2EE)快速开发框架, ...

  7. js正则判断日期

    //****************************************************************************// Function ID : Commo ...

  8. Android学习笔记_35_PopupWindow泡泡窗口的实现及GridView应用

    1.PopupWindow是一个可以显示在当前Activity之上的浮动容器,PopupWindow弹出的位置是能够改变的,按照有无偏移量,可以分为无偏移和有便宜两种:按照参照对象的不同又可以分为两种 ...

  9. caffe convert mxnet

    https://github.com/apache/incubator-mxnet/tree/430ea7bfbbda67d993996d81c7fd44d3a20ef846/tools/caffe_ ...

  10. box-shadow的应用技巧

    一.box-shadow的参数解析 box-shadow:none; box-shadow: h-shadow v-shadow blur spread color inset; box-shadow ...