如果找的是core的HttpClientFactory 出门右转。

  1. 官方写法,高并发下,TCP连接不能快速释放,导致端口占完,无法连接

    Dispose 不是马上关闭tcp连接

    主动关闭的一方为什么不能马上close而是进入timewait状态:TCP四次挥手客户端关闭链接为什么要等待2倍MSL

    正确写法一个域(一个地址) 保证一个静态httpclient操作,保证重用tcp连接。

  2. 如果HttpClient唯一,如果请求头内容需要变化怎么办,异常:"集合已修改;可能无法执行枚举操作"

    HttpClient有个接口SendAsync。看源码知道其实HttpClient内部get,post,put,delete最终都是调用SendAsync。

    这个方法可以允许用户传递HttpRequestMessage,内部包含(HttpRequestHeaders)

  3. HttpClient 死锁

    关于Task同步上下文 造成死锁问题就不多解释。避免方法就是ConfigureAwait(false)或者await always。最好是await always。传送门

    说下不用await 而使用类似HttpClient.GetStringAsync(uri).Result 直接同步获取为什么没有死锁

    因为HttpClient源码里面用到async await的地方几乎都加了ConfigureAwait(false)。233333

  4. 预热和长连接

    其实这是嘴巴dudu园长大人在很久以前就做分析过 传送门

  5. HttpClient 利用stream和json.net 减少内存开销,加快反序列化过程

    我们一般的请求流程:发起请求,获取返回的string对象,然后反序列化成我们想要的对象。而其实可以利用stream直接反序列化成我们想要的对象。

    而且可以是在HttpCompletionOption.ResponseHeadersRead的情况下。传送门

    封印:

     /// <summary>
    /// 异步http请求者。
    /// 注意:杜绝new的形式,可以IOC容器单例注入
    /// 如果多个address地址,通过name key形式注入多个单例
    /// </summary>
    public class HttpAsyncSender
    {
    private readonly ILogger _logger = LoggerManager.GetLogger(typeof(HttpAsyncSender));
    //静态 重用tcp连接 长连接(not dispose)https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
    private readonly HttpClient _httpClient = new HttpClient(); public HttpAsyncSender(Uri baseUri, int timeoutSeconds = , bool keepAlive = true, bool preheating = false, long maxResponseContentBufferSize = )
    {
    //基础地址
    _httpClient.BaseAddress = baseUri;
    //超时
    if (timeoutSeconds != )
    {
    _httpClient.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
    }
    //response最大接收字节 默认2gbmstsc
    if (maxResponseContentBufferSize != )
    {
    _httpClient.MaxResponseContentBufferSize = maxResponseContentBufferSize;
    }
    //长连接 //https://www.cnblogs.com/lori/p/7692152.html http 1.1 default set keep alive
    if (keepAlive)
    {
    _httpClient.DefaultRequestHeaders.Connection.Add("keep-alive");
    }
    //httpclient 预热 the first request //https://www.cnblogs.com/dudu/p/csharp-httpclient-attention.html
    if (preheating)
    {
    _httpClient.SendAsync(new HttpRequestMessage
    {
    Method = new HttpMethod("HEAD"),
    RequestUri = new Uri(baseUri + "/")
    }).Result.EnsureSuccessStatusCode();
    }
    } #region 异步 /// <summary>
    /// GetAsync 注意 await always
    /// </summary>
    /// <param name="url"></param>
    /// <param name="cancellationToken"></param>
    /// <param name="jsonSerializerSettings"></param>
    /// <returns></returns>
    public async Task<T> GetAsync<T>(string url, CancellationToken cancellationToken, JsonSerializerSettings jsonSerializerSettings = null)
    {
    try
    {
    //https://johnthiriet.com/efficient-api-calls/ 减少内存开销 利用stream特性 加快反序列化
    using (var request = new HttpRequestMessage(HttpMethod.Get, url))
    {
    var res = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
    var resStesam = await res.Content.ReadAsStreamAsync().ConfigureAwait(false);
    if (res.IsSuccessStatusCode)
    {
    return DeserializeJsonFromStream<T>(resStesam, jsonSerializerSettings);
    }
    var resStr = await StreamToStringAsync(resStesam).ConfigureAwait(false);
    _logger.Error($"HttpAsyncSender, GetAsync ,response fail StatusCode:{res.StatusCode} resStr:{resStr} BaseAddress:{_httpClient.BaseAddress},Url:{url}");
    }
    }
    catch (AggregateException ae)
    {
    _logger.Error($"HttpAsyncSender,GetAsync AggregateException,BaseAddress:{_httpClient.BaseAddress},Url:{url} ae:{ae.Flatten()}");
    throw; }
    catch (Exception e)
    {
    _logger.Error($"HttpAsyncSender,GetAsync Exception,BaseAddress:{_httpClient.BaseAddress},Url:{url}",e);
    throw;
    } return default(T);
    } /// <summary>
    /// PostAsync 注意 await always
    /// </summary>
    /// <param name="url"></param>
    /// <param name="content"></param>
    /// <param name="cancellationToken"></param>
    /// <param name="jsonSerializerSettings"></param>
    /// <returns></returns>
    public async Task<TRes> PostAsync<TReq, TRes>(string url, TReq content, CancellationToken cancellationToken, JsonSerializerSettings jsonSerializerSettings = null)
    {
    try
    {
    //https://johnthiriet.com/efficient-api-calls/ 减少内存开销 利用stream特性 加快反序列化
    using (var request = new HttpRequestMessage(HttpMethod.Post, url))
    using (var httpContent = CreateHttpContent(content, jsonSerializerSettings))
    {
    request.Content = httpContent;
    var res = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
    var resStesam = await res.Content.ReadAsStreamAsync().ConfigureAwait(false);
    if (res.IsSuccessStatusCode)
    {
    return DeserializeJsonFromStream<TRes>(resStesam, jsonSerializerSettings);
    }
    var resStr = await StreamToStringAsync(resStesam).ConfigureAwait(false);
    _logger.Error($"HttpAsyncSender, PostAsync ,response fail StatusCode:{res.StatusCode} resStr:{resStr} BaseAddress:{_httpClient.BaseAddress},Url:{url}");
    }
    }
    catch (AggregateException ae)
    {
    _logger.Error($"HttpAsyncSender,PostAsync AggregateException,BaseAddress:{_httpClient.BaseAddress},Url:{url} ae:{ae.Flatten()}");
    throw; }
    catch (Exception e)
    {
    _logger.Error($"HttpAsyncSender,PostAsync Exception,BaseAddress:{_httpClient.BaseAddress},Url:{url}",e);
    throw;
    } return default(TRes);
    } /// <summary>
    /// SendAsync 注意 await always 当需要动态改变request head的时候 调用此方法。 解决 "集合已修改;可能无法执行枚举操作"
    /// </summary>
    /// <param name="httpRequestMessage"></param>
    /// <param name="completionOption"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage httpRequestMessage, HttpCompletionOption completionOption, CancellationToken cancellationToken)
    {
    try
    {
    return await _httpClient.SendAsync(httpRequestMessage, completionOption, cancellationToken).ConfigureAwait(false);
    }
    catch (AggregateException ae)
    {
    _logger.Error(
    $"HttpAsyncSender,SendAsync AggregateException,BaseAddress:{_httpClient.BaseAddress},Url:{httpRequestMessage.RequestUri} ae:{ae.Flatten()}");
    throw; }
    catch (Exception e)
    {
    _logger.Error($"HttpAsyncSender,SendAsync Exception,BaseAddress:{_httpClient.BaseAddress},Url:{httpRequestMessage.RequestUri}",e);
    throw;
    }
    } #endregion private T DeserializeJsonFromStream<T>(Stream stream, JsonSerializerSettings jsonSerializerSettings = null)
    {
    if (stream == null || stream.CanRead == false)
    return default(T); using (var sr = new StreamReader(stream))
    using (var jtr = new JsonTextReader(sr))
    {
    var js = jsonSerializerSettings == null ? new JsonSerializer() : JsonSerializer.Create(jsonSerializerSettings);
    var searchResult = js.Deserialize<T>(jtr);
    return searchResult;
    }
    } private async Task<string> StreamToStringAsync(Stream stream)
    {
    string content = null; if (stream != null)
    using (var sr = new StreamReader(stream))
    content = await sr.ReadToEndAsync(); return content;
    } public void SerializeJsonIntoStream(object value, Stream stream, JsonSerializerSettings jsonSerializerSettings = null)
    {
    using (var sw = new StreamWriter(stream, new UTF8Encoding(false), , true))
    using (var jtw = new JsonTextWriter(sw) { Formatting = Formatting.None })
    {
    var js = jsonSerializerSettings==null?new JsonSerializer():JsonSerializer.Create(jsonSerializerSettings);
    js.Serialize(jtw, value);
    jtw.Flush();
    }
    } private HttpContent CreateHttpContent<T>(T content, JsonSerializerSettings jsonSerializerSettings = null)
    {
    HttpContent httpContent = null;
    if (content != null)
    {
    var ms = new MemoryStream();
    SerializeJsonIntoStream(content, ms, jsonSerializerSettings);
    ms.Seek(, SeekOrigin.Begin);
    httpContent = new StreamContent(ms);
    httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    } return httpContent;
    }
    }

9102年了,汇总下HttpClient问题,封印一个的更多相关文章

  1. Cocos开发中Visual Studio下HttpClient开发环境设置

    Cocos2d-x 3.x将与网络通信相关的类集成到libNetwork类库工程中,这其中包括了HttpClient类.我们需要在Visual Studio解决方案中添加libNetwork类库工程. ...

  2. .Net45下HttpClient的几个缺陷

    前言 最近在写WebClientApi这个组件,底层使用HttpClient,发现HttpClient有许多低级的错误,使用者一不小心就可能会正常的去调用它的这些错误,得不到预期的结果.本文我把我认为 ...

  3. Swift技术之如何在iOS 8下使用Swift设计一个自定义的输入法 (主要是NSLayoutConstraint 的使用)

    当前位置: > Swift新手入门 > Swift技术之如何在iOS 8下使用Swift设计一个自定义的输入法 时间:2014-09-10 16:49来源:未知 作者:啊成 举报 点击:5 ...

  4. Eclipse 下如何引用另一个项目的Java文件

    有关联的2个项目,有些类是相同的.例如实体类. 如果你采用 Ctrl + C & Ctrl + V 的方式,以后再有改动,2个项目就都需要改动. 怎样才能只改动一个呢? 答案就是,在一个项目( ...

  5. Eclipse 下如何引用另一个项目的资源文件

    为什么要这么做?可参考:Eclipse 下如何引用另一个项目的Java文件 下面直接说下步骤:(项目A 引用 项目B的资源文件) 1.右键 项目A,点击菜单 Properties 2.在弹出的框中,点 ...

  6. Qt ------ window下工程项目打包成一个exe程序

    最近,在学习QT5的过程中,想尝试着把自己写的工程程序给打包发布出来,在任何一台windows系统都能运行,这样就不会限于电脑需不需要安装QT安装包了. 首先,先介绍自己使用的环境.我使用的QT版本是 ...

  7. 在Linux下,如何分析一个程序达到性能瓶颈的原因

    0.在Linux下,如何分析一个程序达到性能瓶颈的原因,请分别从CPU.内存.IO.网络的角度判断是谁导致的瓶颈?注意现在的机器CPU是多核 1.用sar -n DEV 1 10 2.用iotop命令 ...

  8. 【小程序】微信小程序打开其他小程序(打开同一主体公众号下关联的另一个小程序)

    微信小程序打开其他小程序(打开同一公众号下关联的另一个小程序) 注:只有同一(主体)公众号下的关联的小程序之间才可相互跳转  wx.navigateToMiniProgram(OBJECT) wx.n ...

  9. PyCharm在同一个包(package)下,如何把一个.py文件导入另外一个.py文件下

    PyCharm在同一个包(package)下,如何把一个.py文件导入另外一个.py文件下 在同一个包下只需要用import 掉以后就可以找到模块所在的位置,但是如果不在同一个包下,在需要返回父级调用 ...

随机推荐

  1. 当Vue中img的src是动态渲染时不显示问题

    最近遇见动态渲染img时,想起了当初刚开始写vue时,曾经遇见的一个小小坑. Vue中:img的src属性是动态渲染时不显示问题1.需求:展示用户头像,数据从后台获取,如果没有拿到则显示默认图片. 如 ...

  2. VS 2017显示“高级保存选项”命令操作方法

    Visual Studio提供“高级保存选项”功能,它能指定特定代码文件的编码规范和行尾所使用的换行符.在Visual Studio 2017中,该命令默认是没有显示在“文件”菜单中的.用户需要手工设 ...

  3. JAVA解决前端跨域问题。

    什么是跨域? 通俗来说,跨域按照我自己的想法来理解,是不同的域名之间的访问,就是跨域.不同浏览器,在对js文件进行解析是不同的,浏览器会默认阻止,所以 现在我来说下用java代码解决前端跨域问题. 用 ...

  4. centos7.6 ssh远程链接配置

    1.firewall增加22端口号 增加方式有两种,直接编辑firewall的public.xml增加 vi /etc/firewalld/zones/public.xml 进入后按i健光标移动到zo ...

  5. flag读取控制台参数

    package main import ( "fmt" "os") func main() { arg := os.Args if len(arg) < ...

  6. 11-jQuery的事件绑定和解绑

    1.绑定事件 语法: bind(type,data,fn) 描述:为每一个匹配元素的特定事件(像click)绑定一个事件处理器函数. 参数解释: type (String) : 事件类型 data ( ...

  7. html图片上传阅览并且点击放大

                  关闭   qq_31540195的博客       目录视图 摘要视图 订阅 异步赠书:9月重磅新书升级,本本经典           程序员9月书讯      每周荐书: ...

  8. 《你不知道的JavaScript》三卷读后感

    本系列的作者是Kyle Simpson,上卷译者赵望野.梁杰,中卷译者单业,下卷译者单业.姜南. 我个人觉得第一卷是本系列最好的(必读),而第二卷虽然也讲解了很多知识点,但是对于异步和性能的那部分提及 ...

  9. Django积木块十——全文检索

    全文检索 全文检索效率更高,对中文可以进行分词 <!--# 1.安装包--> pip install django-haystack pip install whoosh pip inst ...

  10. karaf 控制台 常用linux指令(1)

    0,切换命令当前域名 -bash代码 *:feature 命令是由域名+命令名组成的,切换当前域名,比如切换到*:feature,那么再输入list,则执行的是feature:list,切换到*:bu ...