WebApi 异步请求(HttpClient)

还是那几句话:

学无止境,精益求精

十年河东,十年河西,莫欺少年穷

学历代表你的过去,能力代表你的现在,学习代表你的将来

废话不多说,直接进入正题:

今天公司总部要求各个分公司把短信接口对接上,所谓的短信接口其实就是GET或者Post请求,接到这个任务感觉好Easy。

但是真正写起来,你会发现各种各样的问题,比如请求报401错误,报400错误,报..等等各种意想不到的错误!总之,在这个过程中尝试了三个方法:

第一个方法如下(由于第一个方法封装的比较多,在此仅仅截图),如下:

WebApi 异步请求(HttpClient)

小矩形内得POST方法,结果发现报400错误。

紧接着我又尝试了第二种方法(这种方法比较简单,一般的POST请求都可以完成)

第二种方法如下(2014年微信公众号开发中,好多请求我都用的这个方法):

WebApi 异步请求(HttpClient)WebApi 异步请求(HttpClient)
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;
            }
        }
View Code

结果这个方法报401错误。

无奈,又在Git Hub上找了个方法,如下:

WebApi 异步请求(HttpClient)WebApi 异步请求(HttpClient)
/*
 * 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*************************");
        }

    }
}
View Code

结果又是没能跳出错误的怪圈,依然是401错误。

于是,我不得不温习下 C#  HttpClient  的相关方法

WebApi 异步请求(HttpClient)

最后,还好,在公司的项目中有这种用到  HttpClient 的方法,于是抱着尝试的心里,作了测试,结果成功了!

本人写这篇博客也是做一个记录,方便自己以后用,也方便大家遇到 WebApi请求失败时,可以尝试上述的几种方法。

代码如下:

WebApi 异步请求(HttpClient)WebApi 异步请求(HttpClient)
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;
        }
    }
}
View Code
WebApi 异步请求(HttpClient)WebApi 异步请求(HttpClient)
        [Route("test"), HttpGet, AllowAnonymous]
        public async Task<IHttpActionResult> test()
        {
            SmsSendHelper Func = new SmsSendHelper();
            var data =await Func.Send("181XXXX0152","你好!短信测试。");
            return Ok(data);
        }
View Code

需要引用如下命名空间:

WebApi 异步请求(HttpClient)

 

总之,很简单,也很好用。

 @陈卧龙的博客

上一篇:Meta标签中的viewport属性及含义


下一篇:meta标签的另一个用法