/// <summary> /// 封装HttpOption的Send扩展方法发送HTTP请求,并提供失败重试功能。 /// 如果遇到WebException异常,就转换成RemoteWebException异常 /// </summary> /// <param name="option">HttpOption实例,用于包含HTTP请求的发送参数</param> /// <param name="retry">提供一个Retry实例,用于指示如何执行重试。如果此参数为NULL则不启用重试</param> /// <returns></returns> public static T GetResult <T>(this HttpOption option, Retry retry = null) { try { if (retry == null) { return(option.Send <T>()); } else { return(retry.Run(option.Send <T>)); } } catch (WebException ex) { // 返回一个容易获取异常消息的异常类型 throw new RemoteWebException(ex, option.Url); } }
/// <summary> /// 封装HttpOption的Send扩展方法发送HTTP请求,并提供失败重试功能。 /// 如果遇到WebException异常,就转换成RemoteWebException异常 /// </summary> /// <param name="option">HttpOption实例,用于包含HTTP请求的发送参数</param> /// <param name="retry">提供一个Retry实例,用于指示如何执行重试。如果此参数为NULL将采用默认重试规则</param> /// <returns></returns> public static T GetResult <T>(this HttpOption option, Retry retry) { if (retry == null) { retry = GetDefaultRetry(); } try { return(retry.Run <T>(() => { return option.Send <T>(); })); } catch (WebException ex) { // 返回一个容易获取异常消息的异常类型 throw new RemoteWebException(ex); } }
/// <summary> /// 封装HttpOption的Send扩展方法发送HTTP请求,并提供失败重试功能。 /// 如果遇到WebException异常,就转换成RemoteWebException异常 /// </summary> /// <param name="option">HttpOption实例,用于包含HTTP请求的发送参数</param> /// <param name="retry">提供一个Retry实例,用于指示如何执行重试。如果此参数为NULL则不启用重试</param> /// <returns></returns> public async static Task <string> GetResultAsync(this HttpOption option, Retry retry = null) { try { if (retry == null) { return(await option.SendAsync()); } else { return(await retry.RunAsync(option.SendAsync)); } } catch (WebException ex) { // 返回一个容易获取异常消息的异常类型 throw new RemoteWebException(ex, option.Url); } }
/// <summary> /// 封装HttpOption的Send扩展方法发送HTTP请求,并提供失败重试功能。 /// 如果遇到WebException异常,就转换成RemoteWebException异常 /// </summary> /// <param name="option">HttpOption实例,用于包含HTTP请求的发送参数</param> /// <param name="retry">提供一个Retry实例,用于指示如何执行重试。如果此参数为NULL将采用默认重试规则</param> /// <returns></returns> public async static Task <string> GetResultAsync(this HttpOption option, Retry retry) { if (retry == null) { retry = GetDefaultRetry(); } try { return(await retry.RunAsync <string>(async() => { return await option.SendAsync(); })); } catch (WebException ex) { // 返回一个容易获取异常消息的异常类型 throw new RemoteWebException(ex); } }
/// <summary> /// 根据指定的HttpOption参数,用【异步】方式发起一次HTTP请求 /// </summary> /// <typeparam name="T">返回值的类型参数</typeparam> /// <param name="option">HttpOption的实例,用于描述请求参数</param> /// <returns>返回服务端的调用结果,并转换成指定的类型</returns> public async static Task <T> SendAsync <T>(this HttpOption option) { if (option == null) { throw new ArgumentNullException("option"); } option.CheckInput(); HttpClient client = ObjectFactory.New <HttpClient>(); bool urlQuery = option.IsMustQueryString(); string requestUrl = option.Url; if (option.Data != null && urlQuery) //GET 请求,需要将参数合并到URL,形成查询字符串参数 { if (option.Url.IndexOf('?') < 0) { requestUrl = option.Url + "?" + GetQueryString(option.Data); } else { requestUrl = option.Url + "&" + GetQueryString(option.Data); } } HttpWebRequest request = client.CreateWebRequest(requestUrl); SetWebRequest(request, option); option.SetRequestAction?.Invoke(request); // 调用委托 if (option.Data != null && urlQuery == false) // POST提交数据 { await client.SetRequestDataAsync(option.Data, option.Format); } using (HttpWebResponse response = await client.GetResponseAsync()) { option.ReadResponseAction?.Invoke(response); // 调用委托 return(client.GetResult <T>(response)); } }
private static void SetWebRequest(HttpWebRequest request, HttpOption option) { request.Method = option.Method; foreach (NameValue item in option.Headers) { request.Headers.InternalAdd(item.Name, item.Value); } if (option.Cookie != null) { request.CookieContainer = option.Cookie; } if (option.Credentials != null) { request.Credentials = option.Credentials; // CredentialCache.DefaultCredentials; } if (option.Timeout.HasValue) { request.Timeout = option.Timeout.Value; } if (string.IsNullOrEmpty(option.ContentType) == false) { request.ContentType = option.ContentType; } if (string.IsNullOrEmpty(option.UserAgent) == false) { request.UserAgent = option.UserAgent; } if (option.DisableAutoRedirect) { request.AllowAutoRedirect = false; } }
/// <summary> /// 根据原始请求信息文本构建 HttpOption 对象(格式可参考Fiddler的Inspectors标签页内容) /// </summary> /// <param name="text"></param> /// <returns></returns> public static HttpOption FromRawText(string text) { // 示例数据: //POST http://www.fish-mvc-demo.com/Ajax/ns/TestAutoAction/submit.aspx HTTP/1.1 //Host: www.fish-mvc-demo.com //User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0 //Accept: */* //Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 //Accept-Encoding: gzip, deflate //Content-Type: application/x-www-form-urlencoded; charset=UTF-8 //X-Requested-With: XMLHttpRequest //Referer: http://www.fish-mvc-demo.com/Pages/Demo/TestAutoFindAction.htm //Content-Length: 72 //Cookie: hasplmlang=_int_; LoginBy=productKey; PageStyle=Style2; //Connection: keep-alive //Pragma: no-cache //Cache-Control: no-cache //input=Fish+Li&Base64=%E8%BD%AC%E6%8D%A2%E6%88%90Base64%E7%BC%96%E7%A0%81 if (string.IsNullOrEmpty(text)) { throw new ArgumentNullException("text"); } HttpOption option = new HttpOption(); option.ContentType = null; using (StringReader reader = new StringReader(text.Trim())) { string firstLine = reader.ReadLine(); int p1 = firstLine.IndexOf(' '); int p2 = firstLine.LastIndexOf(' '); if (p1 < 0 || p1 == p2) { throw new ArgumentException("不能识别的请求文本格式。"); } option.Method = firstLine.Substring(0, p1); // 不使用HTTP协议版本,只做校验。 string httpVersion = firstLine.Substring(p2 + 1); if (httpVersion.StartsWith("HTTP/") == false) { throw new ArgumentException("不能识别的请求文本格式。"); } option.Url = firstLine.Substring(p1 + 1, p2 - p1 - 1); string line = null; while ((line = reader.ReadLine()) != null) { if (line.Length > 0) { // 处理请求头 int p3 = line.IndexOf(':'); if (p3 > 0) { string name = line.Substring(0, p3); string value = line.Substring(p3 + 2); // 2 表示2个字符,一个冒号,一个空格 option.Headers.Add(name, value); } else { throw new ArgumentException("不能识别的请求文本格式。"); } } else { break; } } // 请求体数据 string postText = reader.ReadToEnd(); if (string.IsNullOrEmpty(postText) == false) { option.Data = postText; } } string contentType = option.Headers["Content-Type"]; if (contentType != null) { int p = contentType.IndexOf("; charset="); // 注意:这里丢弃了 charset 设置,因为 HttpClient 固定以 utf-8 编码方式发送请求! if (p > 0) { option.ContentType = contentType.Substring(0, p); } else { option.ContentType = contentType; } option.Headers.Remove("Content-Type"); } return(option); }
/// <summary> /// 根据指定的HttpOption参数,用【异步】方式发起一次HTTP请求 /// </summary> /// <param name="option">HttpOption的实例,用于描述请求参数</param> /// <returns>返回服务端的调用结果,并转换成指定的类型</returns> public async static Task <string> SendAsync(this HttpOption option) { return(await SendAsync <string>(option)); }
/// <summary> /// 根据指定的HttpOption参数,用【同步】方式发起一次HTTP请求 /// </summary> /// <param name="option">HttpOption的实例,用于描述请求参数</param> /// <returns>返回服务端的调用结果,并转换成指定的类型</returns> public static string Send(this HttpOption option) { return(Send <string>(option)); }