/// <summary> /// http 同步请求类 /// 如果类库中没有提供设置HttpWebRequest参数的方法,可以实现OnCreatedRequest回调,自己再去设置 /// 有任何错误可以判断Exception类型,获取相应错误信息 /// </summary> public class HttpClient { private Encoding respEncoding = Encoding.UTF8; #if DEBUG private int timeout = Int32.MaxValue; #else private int timeout = 30000; #endif /// <summary> /// 字符编码 /// </summary> public Encoding DefaultEncoding { get; set; } = Encoding.UTF8; /// <summary> /// 当HttpWebRequest创建完成回调 /// </summary> public Action<HttpWebRequest> OnCreatedRequest { get; set; } /// <summary> /// 设置超时时间,默认30秒,单位毫秒 /// </summary> /// <param name="timeout"></param> public void SetTimeout(int timeout) { this.timeout = timeout; } /// <summary> /// 请求报文头 /// </summary> public Dictionary<string, string> Headers { get; set; } = new Dictionary<string, string>(); /// <summary> /// 异常信息 /// </summary> public Exception Exception { get; set; } /// <summary> /// HttpStatusCode /// </summary> public HttpStatusCode HttpStatusCode { get; set; } /// <summary> /// 同步Get /// </summary> /// <param name="url">路径</param> /// <returns>返回</returns> public string Get(string url) { var httpWebRequest = CreateHttpWebRequest(url); httpWebRequest.Method = "GET"; //返回数据s var bytes = GetRespBytes(httpWebRequest); return bytes != null ? respEncoding.GetString(bytes) : null; } /// <summary> /// 同步post /// </summary> /// <param name="url">地址</param> /// <param name="postStr">数据</param> /// <param name="isjson">是否是json数据,默认false</param> /// <returns>返回</returns> public string Post(string url, string postStr = null, bool isjson = false) { return Post(url, string.IsNullOrEmpty(postStr) ? null : DefaultEncoding.GetBytes(postStr), isjson); } /// <summary> /// 同步post /// </summary> /// <param name="url">地址</param> /// <param name="contentBytes">内容的byte字节</param> /// <param name="isjson">是否是json数据,默认false</param> /// <returns>返回</returns> public string Post(string url, byte[] contentBytes = null, bool isjson = false) { HttpWebRequest httpWebRequest = CreateHttpWebRequest(url, isjson); httpWebRequest.Method = "POST"; //写数据 if (contentBytes != null && contentBytes.Length > 0) { httpWebRequest.ContentLength = contentBytes.Length; try { using (var myStream = httpWebRequest.GetRequestStream()) { myStream.Write(contentBytes, 0, contentBytes.Length); } } catch (Exception ex) { Exception = ex; return null; } } //返回数据 var bytes = GetRespBytes(httpWebRequest); return bytes != null ? respEncoding.GetString(bytes) : null; } /// <summary> /// 获取返回数据 /// </summary> /// <param name="httpWebRequest"></param> /// <returns>返回</returns> private byte[] GetRespBytes(HttpWebRequest httpWebRequest) { //接收数据 using (HttpWebResponse httpResp = GetHttpWebResponse(httpWebRequest)) { Stream respStream = httpResp?.GetResponseStream(); if (respStream == null) return null; using (Stream stream = httpResp.ContentEncoding.ToLower().Contains("gzip") ? new GZipStream(respStream, CompressionMode.Decompress) : respStream) { List<byte> lst = new List<byte>(); int nRead; while ((nRead = stream.ReadByte()) != -1) lst.Add((byte)nRead); var bytes = lst.ToArray(); //获取编码 respEncoding = GetHtmlEncoding(httpResp, bytes); return bytes; } } } /// <summary> /// 创建HttpWebRequest /// </summary> /// <param name="url">url地址</param> /// <param name="isjson">是否是json数据,默认false</param> /// <returns>返回</returns> private HttpWebRequest CreateHttpWebRequest(string url, bool isjson = false) { var httpWebRequest = (HttpWebRequest)WebRequest.Create(url); HttpStatusCode = HttpStatusCode.Created; httpWebRequest.Accept = "text/html, application/xhtml+xml, */*"; httpWebRequest.ContentType = "application/x-www-form-urlencoded;charset=" + DefaultEncoding.WebName; if (isjson) httpWebRequest.ContentType = "application/json;charset=" + DefaultEncoding.WebName; httpWebRequest.UserAgent = "Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0;)"; //httpWebRequest.UserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_2 like Mac OS X) AppleWebKit/602.3.12 (KHTML, like Gecko) Mobile/14C92 Safari/601.1 wechatdevtools/0.18.182200 MicroMessenger/6.5.7 Language/zh_CN webview/0)"; httpWebRequest.ProtocolVersion = HttpVersion.Version11; httpWebRequest.Headers.Add("Accept-Language", "zh-cn"); httpWebRequest.Headers.Add("Accept-Encoding", "gzip, deflate"); httpWebRequest.Headers.Add("Pragma", "no-cache"); httpWebRequest.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore); httpWebRequest.KeepAlive = true; //httpWebRequest.AllowAutoRedirect = true; httpWebRequest.ServicePoint.Expect100Continue = false; httpWebRequest.Timeout = timeout; //添加header if (Headers.Count > 0) { foreach (var header in Headers) httpWebRequest.Headers.Add(header.Key, header.Value); } if (url.Contains("https://")) SetCertificatePolicy(); OnCreatedRequest?.Invoke(httpWebRequest); return httpWebRequest; } /// <summary> /// 获取HttpWebResponse /// </summary> /// <param name="httpWebRequest"></param> /// <returns>返回</returns> private HttpWebResponse GetHttpWebResponse(HttpWebRequest httpWebRequest) { HttpWebResponse httpResp = null; try { httpResp = (HttpWebResponse)httpWebRequest.GetResponse(); HttpStatusCode = httpResp.StatusCode; } catch (WebException ex) { Exception = ex; if (ex.Response != null) { httpResp = (HttpWebResponse) ex.Response; HttpStatusCode = httpResp.StatusCode; } } catch (Exception ex) { Exception = ex; } return httpResp; } /// <summary> /// 从html内容获取编码 /// </summary> /// <param name="response"></param> /// <param name="bytes"></param> /// <returns>返回</returns> private Encoding GetHtmlEncoding(HttpWebResponse response, byte[] bytes) { Encoding encoding = DefaultEncoding; //检测响应头是否返回了编码类型,若返回了编码类型则使用返回的编码 //注:有时响应头没有编码类型,CharacterSet经常设置为ISO-8859-1 if (!string.IsNullOrEmpty(response.CharacterSet) && response.CharacterSet.ToUpper() != "ISO-8859-1") { encoding = Encoding.GetEncoding(response.CharacterSet == "utf8" ? "utf-8" : response.CharacterSet); } else { //若没有在响应头找到编码,则去html找meta头的charset var result = Encoding.Default.GetString(bytes); //在返回的html里使用正则匹配页面编码 Match match = Regex.Match(result, @"<meta.*charset=""?([\w-]+)""?.*>", RegexOptions.IgnoreCase); if (match.Success) { encoding = Encoding.GetEncoding(match.Groups[1].Value); } } return encoding; } /// <summary> /// 注册证书 /// </summary> private void SetCertificatePolicy() { ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidate; } /// <summary> /// 远程证书验证,固定返回true /// </summary> private bool RemoteCertificateValidate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors error) { return true; } }