最近在公司項目中使用了HttpWebRequst相關API,運行環境為.Net/Mono 2.0,是一款針對Unity平台的工具。開發過程中碰到了大家可能都碰到過的問題,Http還是Https? 為什么Http可以正常響應,Https就會失敗,返回結果為authorize or decrypt failed.
by th way, .Net 4.0及以上版本好像已經沒有這個問題了,巨硬默默把坑填了。
使用Http的寫法:
public void Get(string Url) { HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create (Url); webRequest.Method="GET"; webRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36"; webRequest.BeginGetResponse(GetResponseCallback,webRequest); } private void GetResponseCallback(IAsyncResult ar) { //RequestState myRequestState = (RequestState)ar.AsyncState; HttpWebRequest webRequest = (HttpWebRequest)ar.AsyncState; try{ WebResponse response = webRequest.EndGetResponse(ar); streamReader = new StreamReader(response.GetResponseStream ()); } catch(Exception es) { Debug.Log (es.Message); } if (GetDataCompleted != null) { GetDataCompleted(this,new GetDataCompletedArgs(streamReader.ReadToEnd ())); } }
這里使用了異步,同步的寫法效果相同。
但是如果此時使用了Https的Url,結果會一直返回失敗。這是為什么呢?原因是Https基於SSL/TLS協議,需要在請求之前進行證書驗證,而我們上面的寫法並沒有進行相關的驗證,所以導致通信失敗。怎么解決此問題呢?很簡單,我們在請求發出前進行驗證,在.Net 2.0或更高版本,我們加入回調函數即可。
解決辦法:
public void Get(string Url) { //SSL/TLS certificate method ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult); HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create (Url); webRequest.Method="GET"; webRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36"; webRequest.BeginGetResponse(GetResponseCallback,webRequest); } /// <summary> /// SSL/TLS certificate callback method /// Must return true /// </summary> /// <returns><c>true</c>, if validation result was checked, <c>false</c> otherwise.</returns> /// <param name="sender">Sender.</param> /// <param name="certificate">Certificate.</param> /// <param name="chain">Chain.</param> /// <param name="sslPolicyErrors">Ssl policy errors.</param> public bool CheckValidationResult (object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, SslPolicyErrors sslPolicyErrors) { //Debug.LogWarning (certificate.GetSerialNumberString ()); return true; } /// <summary> /// Gets the response callback. /// </summary> /// <param name="ar">Ar.</param> private void GetResponseCallback(IAsyncResult ar) { //RequestState myRequestState = (RequestState)ar.AsyncState; HttpWebRequest webRequest = (HttpWebRequest)ar.AsyncState; try{ WebResponse response = webRequest.EndGetResponse(ar); streamReader = new StreamReader(response.GetResponseStream ()); } catch(Exception es) { Debug.Log (es.Message); } if (GetDataCompleted != null) { GetDataCompleted(this,new GetDataCompletedArgs(streamReader.ReadToEnd ())); } }
至此就可以,解決此問題,這類問題說大不大,說小不小,屬於我們開發中遇到的小坑之一,.Net4.0以上版本不需注意此問題。
關於更低的.Net 1.1的寫法,大家可以去看一下博客,本篇博文也是參照他的解決方案:
http://blog.sina.com.cn/s/blog_4ae95c270101qnn1.html