/// <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;
}
}