還是那幾句話:
學無止境,精益求精
十年河東,十年河西,莫欺少年窮
學歷代表你的過去,能力代表你的現在,學習代表你的將來
廢話不多說,直接進入正題:
今天公司總部要求各個分公司把短信接口對接上,所謂的短信接口其實就是GET或者Post請求,接到這個任務感覺好Easy。
但是真正寫起來,你會發現各種各樣的問題,比如請求報401錯誤,報400錯誤,報..等等各種意想不到的錯誤!總之,在這個過程中嘗試了三個方法:
第一個方法如下(由於第一個方法封裝的比較多,在此僅僅截圖),如下:
小矩形內得POST方法,結果發現報400錯誤。
緊接着我又嘗試了第二種方法(這種方法比較簡單,一般的POST請求都可以完成)
第二種方法如下(2014年微信公眾號開發中,好多請求我都用的這個方法):

public static string GetPage(string posturl, string postData) { //WX_SendNews news = new WX_SendNews(); //posturl: news.Posturl; //postData:news.PostData; System.IO.Stream outstream = null; Stream instream = null; StreamReader sr = null; HttpWebResponse response = null; HttpWebRequest request = null; Encoding encoding = Encoding.UTF8; byte[] data = encoding.GetBytes(postData); // 准備請求... try { // 設置參數 request = WebRequest.Create(posturl) as HttpWebRequest; CookieContainer cookieContainer = new CookieContainer(); request.CookieContainer = cookieContainer; request.AllowAutoRedirect = true; request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = data.Length; outstream = request.GetRequestStream(); outstream.Write(data, 0, data.Length); outstream.Close(); //發送請求並獲取相應回應數據 response = request.GetResponse() as HttpWebResponse; //直到request.GetResponse()程序才開始向目標網頁發送Post請求 instream = response.GetResponseStream(); sr = new StreamReader(instream, encoding); //返回結果網頁(html)代碼 string content = sr.ReadToEnd(); string err = string.Empty; return content; } catch (Exception ex) { string err = ex.Message; return string.Empty; } }
結果這個方法報401錯誤。
無奈,又在Git Hub上找了個方法,如下:

/* * Created by SharpDevelop. * User: RedXu * Date: 2015-04-16 * Time: 13:58 * */ using System; using System.Net; using System.IO; using System.Text; using System.Collections.Generic; using System.Diagnostics; using System.Net.Security; using System.Security.Cryptography.X509Certificates; namespace RedXuCSharpClass { /// <summary> /// Http操作類. /// </summary> public class HttpHelper { private const int ConnectionLimit = 100; //編碼 private Encoding _encoding = Encoding.Default; //瀏覽器類型 private string[] _useragents = new string[]{ "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)", "Mozilla/5.0 (Windows NT 6.1; rv:36.0) Gecko/20100101 Firefox/36.0", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:31.0) Gecko/20130401 Firefox/31.0" }; private String _useragent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.90 Safari/537.36"; //接受類型 private String _accept = "text/html, application/xhtml+xml, application/xml, */*"; //超時時間 private int _timeout = 30 * 1000; //類型 private string _contenttype = "application/x-www-form-urlencoded"; //cookies private String _cookies = ""; //cookies private CookieCollection _cookiecollection; //custom heads private Dictionary<string, string> _headers = new Dictionary<string, string>(); public HttpHelper() { _headers.Clear(); //隨機一個useragent _useragent = _useragents[new Random().Next(0, _useragents.Length)]; //解決性能問題? ServicePointManager.DefaultConnectionLimit = ConnectionLimit; } public void InitCookie() { _cookies = ""; _cookiecollection = null; _headers.Clear(); } /// <summary> /// 設置當前編碼 /// </summary> /// <param name="en"></param> public void SetEncoding(Encoding en) { _encoding = en; } /// <summary> /// 設置UserAgent /// </summary> /// <param name="ua"></param> public void SetUserAgent(String ua) { _useragent = ua; } public void RandUserAgent() { _useragent = _useragents[new Random().Next(0, _useragents.Length)]; } public void SetCookiesString(string c) { _cookies = c; } /// <summary> /// 設置超時時間 /// </summary> /// <param name="sec"></param> public void SetTimeOut(int msec) { _timeout = msec; } public void SetContentType(String type) { _contenttype = type; } public void SetAccept(String accept) { _accept = accept; } /// <summary> /// 添加自定義頭 /// </summary> /// <param name="key"></param> /// <param name="ctx"></param> public void AddHeader(String key, String ctx) { //_headers.Add(key,ctx); _headers[key] = ctx; } /// <summary> /// 清空自定義頭 /// </summary> public void ClearHeader() { _headers.Clear(); } /// <summary> /// 獲取HTTP返回的內容 /// </summary> /// <param name="response"></param> /// <returns></returns> private String GetStringFromResponse(HttpWebResponse response) { String html = ""; try { Stream stream = response.GetResponseStream(); StreamReader sr = new StreamReader(stream, _encoding); html = sr.ReadToEnd(); sr.Close(); stream.Close(); } catch (Exception e) { Trace.WriteLine("GetStringFromResponse Error: " + e.Message); } return html; } /// <summary> /// 檢測證書 /// </summary> /// <param name="sender"></param> /// <param name="certificate"></param> /// <param name="chain"></param> /// <param name="errors"></param> /// <returns></returns> private bool CheckCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; } /// <summary> /// 發送GET請求 /// </summary> /// <param name="url"></param> /// <returns></returns> public String HttpGet(String url) { return HttpGet(url, url); } /// <summary> /// 發送GET請求 /// </summary> /// <param name="url"></param> /// <param name="refer"></param> /// <returns></returns> public String HttpGet(String url, String refer) { String html; try { ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckCertificate); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); request.UserAgent = _useragent; request.Timeout = _timeout; request.ContentType = _contenttype; request.Accept = _accept; request.Method = "GET"; request.Referer = refer; request.KeepAlive = true; request.AllowAutoRedirect = true; request.UnsafeAuthenticatedConnectionSharing = true; request.CookieContainer = new CookieContainer(); //據說能提高性能 request.Proxy = null; if (_cookiecollection != null) { foreach (Cookie c in _cookiecollection) { c.Domain = request.Host; } request.CookieContainer.Add(_cookiecollection); } foreach (KeyValuePair<String, String> hd in _headers) { request.Headers[hd.Key] = hd.Value; } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); html = GetStringFromResponse(response); if (request.CookieContainer != null) { response.Cookies = request.CookieContainer.GetCookies(request.RequestUri); } if (response.Cookies != null) { _cookiecollection = response.Cookies; } if (response.Headers["Set-Cookie"] != null) { string tmpcookie = response.Headers["Set-Cookie"]; _cookiecollection.Add(ConvertCookieString(tmpcookie)); } response.Close(); return html; } catch (Exception e) { Trace.WriteLine("HttpGet Error: " + e.Message); return String.Empty; } } /// <summary> /// 獲取MINE文件 /// </summary> /// <param name="url"></param> /// <returns></returns> public Byte[] HttpGetMine(String url) { Byte[] mine = null; try { ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckCertificate); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); request.UserAgent = _useragent; request.Timeout = _timeout; request.ContentType = _contenttype; request.Accept = _accept; request.Method = "GET"; request.Referer = url; request.KeepAlive = true; request.AllowAutoRedirect = true; request.UnsafeAuthenticatedConnectionSharing = true; request.CookieContainer = new CookieContainer(); //據說能提高性能 request.Proxy = null; if (_cookiecollection != null) { foreach (Cookie c in _cookiecollection) c.Domain = request.Host; request.CookieContainer.Add(_cookiecollection); } foreach (KeyValuePair<String, String> hd in _headers) { request.Headers[hd.Key] = hd.Value; } HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream stream = response.GetResponseStream(); MemoryStream ms = new MemoryStream(); byte[] b = new byte[1024]; while (true) { int s = stream.Read(b, 0, b.Length); ms.Write(b, 0, s); if (s == 0 || s < b.Length) { break; } } mine = ms.ToArray(); ms.Close(); if (request.CookieContainer != null) { response.Cookies = request.CookieContainer.GetCookies(request.RequestUri); } if (response.Cookies != null) { _cookiecollection = response.Cookies; } if (response.Headers["Set-Cookie"] != null) { _cookies = response.Headers["Set-Cookie"]; } stream.Close(); stream.Dispose(); response.Close(); return mine; } catch (Exception e) { Trace.WriteLine("HttpGetMine Error: " + e.Message); return null; } } /// <summary> /// 發送POST請求 /// </summary> /// <param name="url"></param> /// <param name="data"></param> /// <returns></returns> public String HttpPost(String url, String data) { return HttpPost(url, data, url); } /// <summary> /// 發送POST請求 /// </summary> /// <param name="url"></param> /// <param name="data"></param> /// <param name="refer"></param> /// <returns></returns> public String HttpPost(String url, String data, String refer) { String html; try { ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckCertificate); HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); request.UserAgent = _useragent; request.Timeout = _timeout; request.Referer = refer; request.ContentType = _contenttype; request.Accept = _accept; request.Method = "POST"; request.KeepAlive = true; request.AllowAutoRedirect = true; request.CookieContainer = new CookieContainer(); //據說能提高性能 request.Proxy = null; if (_cookiecollection != null) { foreach (Cookie c in _cookiecollection) { c.Domain = request.Host; if (c.Domain.IndexOf(':') > 0) c.Domain = c.Domain.Remove(c.Domain.IndexOf(':')); } request.CookieContainer.Add(_cookiecollection); } foreach (KeyValuePair<String, String> hd in _headers) { request.Headers[hd.Key] = hd.Value; } byte[] buffer = _encoding.GetBytes(data.Trim()); request.ContentLength = buffer.Length; request.GetRequestStream().Write(buffer, 0, buffer.Length); request.GetRequestStream().Close(); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); html = GetStringFromResponse(response); if (request.CookieContainer != null) { response.Cookies = request.CookieContainer.GetCookies(request.RequestUri); } if (response.Cookies != null) { _cookiecollection = response.Cookies; } if (response.Headers["Set-Cookie"] != null) { string tmpcookie = response.Headers["Set-Cookie"]; _cookiecollection.Add(ConvertCookieString(tmpcookie)); } response.Close(); return html; } catch (Exception e) { Trace.WriteLine("HttpPost Error: " + e.Message); return String.Empty; } } public string UrlEncode(string str) { StringBuilder sb = new StringBuilder(); byte[] byStr = _encoding.GetBytes(str); for (int i = 0; i < byStr.Length; i++) { sb.Append(@"%" + Convert.ToString(byStr[i], 16)); } return (sb.ToString()); } /// <summary> /// 轉換cookie字符串到CookieCollection /// </summary> /// <param name="ck"></param> /// <returns></returns> private CookieCollection ConvertCookieString(string ck) { CookieCollection cc = new CookieCollection(); string[] cookiesarray = ck.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < cookiesarray.Length; i++) { string[] cookiesarray_2 = cookiesarray[i].Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); for (int j = 0; j < cookiesarray_2.Length; j++) { string[] cookiesarray_3 = cookiesarray_2[j].Trim().Split("=".ToCharArray()); if (cookiesarray_3.Length == 2) { string cname = cookiesarray_3[0].Trim(); string cvalue = cookiesarray_3[1].Trim(); if (cname.ToLower() != "domain" && cname.ToLower() != "path" && cname.ToLower() != "expires") { Cookie c = new Cookie(cname, cvalue); cc.Add(c); } } } } return cc; } public void DebugCookies() { Trace.WriteLine("**********************BEGIN COOKIES*************************"); foreach (Cookie c in _cookiecollection) { Trace.WriteLine(c.Name + "=" + c.Value); Trace.WriteLine("Path=" + c.Path); Trace.WriteLine("Domain=" + c.Domain); } Trace.WriteLine("**********************END COOKIES*************************"); } } }
結果又是沒能跳出錯誤的怪圈,依然是401錯誤。
於是,我不得不溫習下 C# HttpClient 的相關方法
最后,還好,在公司的項目中有這種用到 HttpClient 的方法,於是抱着嘗試的心里,作了測試,結果成功了!
本人寫這篇博客也是做一個記錄,方便自己以后用,也方便大家遇到 WebApi請求失敗時,可以嘗試上述的幾種方法。
代碼如下:

using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace KMHC.Infrastructure { public class SmsSendHelper { public string _appKey = ""; public string _category = ""; public string _templateNo = ""; public string _templateid = ""; public SmsSendHelper() { } public async Task<SmsSendResult> Send(string phone, string sendContent) { var Model = BuildData(phone, sendContent); SmsSendResult Result = new SmsSendResult(); var hh = new HttpClient() { BaseAddress = new Uri(SmsUri.SmsSendUri), Timeout = TimeSpan.FromMinutes(30) }; //Model 需要序列化的對象 var res = await hh.PostAsJsonAsync("", Model); if (res.StatusCode == HttpStatusCode.OK) { var response = res.Content.ReadAsAsync<SmsSendResult>().Result; return response; } return null; } /// <summary> /// 構建請求實體 /// </summary> /// <param name="_phone"></param> /// <param name="_sendContent"></param> /// <returns></returns> private object BuildData(string _phone, string _sendContent) { var para = new { appKey = _appKey, category = _category, templateNo = _templateNo, templateid = _templateid, phone = _phone, sendContent = _sendContent }; return para; } } }

[Route("test"), HttpGet, AllowAnonymous] public async Task<IHttpActionResult> test() { SmsSendHelper Func = new SmsSendHelper(); var data =await Func.Send("181XXXX0152","你好!短信測試。"); return Ok(data); }
需要引用如下命名空間:
總之,很簡單,也很好用。
@陳卧龍的博客