还是那几句话:
学无止境,精益求精
十年河东,十年河西,莫欺少年穷
学历代表你的过去,能力代表你的现在,学习代表你的将来
废话不多说,直接进入正题:
今天公司总部要求各个分公司把短信接口对接上,所谓的短信接口其实就是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); }
需要引用如下命名空间:
总之,很简单,也很好用。
@陈卧龙的博客