首页 新闻 会员 周边

.net core开发,通过HttpClient调用WebApi,站点线程数增多导致站点打不开

0
悬赏园豆:100 [已解决问题] 解决于 2020-04-27 15:32

使用.net core开发,视图页数据通过HttpClient调用core WebApi的接口,但是时常出现站点(部署在IIS)打开缓慢或者打不开的情况。此时查看任务管理器,发现该站点的线程数增长到好几百了,此时把该进程结束掉,站点就回复正常了,请问各位是哪里出现了问题,怎样解决排查?

如图所示:73是该站点在任务管理器中的线程数,此时正常,如果到三五百站点就挂了。

Impossible的主页 Impossible | 初学一级 | 园豆:72
提问于:2018-05-17 11:14
< >
分享
最佳答案
0

把声明 HttpClient 的地方改为 static 试试

收获园豆:100
dudu | 高人七级 |园豆:30979 | 2018-05-17 11:29

wo看过你先前写的关于HTTPClient的文章,

这是我参考写的

private static HttpClient client;

 static HttpHelper() {

  client = new HttpClient();

}

 

public async Task<string> GetRequest(string url, string token = "")
{
      client.DefaultRequestHeaders.Accept.Add(new              MediaTypeWithQualityHeaderValue("application/json"));
  if (!string.IsNullOrEmpty(token))//需要登录
  {
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer",     token);
  }
  HttpResponseMessage msg = await client.GetAsync(url);
  HttpStatusCode statusCode = msg.StatusCode;
  var result = await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
  return result;
}

然后报错:HTTP Error 400. The size of the request headers is too long.

如果我每次实例化HTTPClient的时候就没这个错误。Token是JWT生成的,长度确实非常大。

Impossible | 园豆:72 (初学一级) | 2018-05-17 13:20

client.DefaultRequestHeaders.Clear();

是不是每次请求前都需要清空一下请求头,要不然会重复发送请求头

Impossible | 园豆:72 (初学一级) | 2018-05-17 13:25

@Impossible: 可以使用 HttpRequestMessage ,示例代码如下:

class Program
{
    private static readonly HttpClient _httpClient = new HttpClient();

    static async Task Main(string[] args)
    {
        var result = await GetRequest("https://q.cnblogs.com");
        Console.WriteLine(result);
    }

    public static async Task<string> GetRequest(string url, string token = "")
    {
        var request = new HttpRequestMessage(HttpMethod.Get, url); 
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        if (!string.IsNullOrEmpty(token))
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        }

        var response = await _httpClient.SendAsync(request);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
    }
}
dudu | 园豆:30979 (高人七级) | 2018-05-17 14:04

@dudu: 已经改成静态HTTPClient的形式了,但是线程数还是一直向上涨。但是程序中除了使用async Task的形式外,没有直接涉及到使用线程的地方,貌似很难找到症结

Impossible | 园豆:72 (初学一级) | 2018-05-17 15:54

@Impossible: 有没有地方在同步方法中调用异步方法

dudu | 园豆:30979 (高人七级) | 2018-05-17 15:55

@dudu: 有,有几个方法中没有用await,直接调用异步方法后使用Result获取值了。

Impossible | 园豆:72 (初学一级) | 2018-05-17 16:44
dudu | 园豆:30979 (高人七级) | 2018-05-17 17:20

@dudu: 经过这今天观察,在某个时候还是会出现线程不停的增长,内存正常。所有的有同步方法调用异步的地方,HttpClient也改为静态的了。在视图中有一部分调用异步方法的代码,有没有可能是这一部分引起的?

@if (ViewContext.HttpContext.User.Identity.IsAuthenticated)
{
    string token = ViewContext.HttpContext.User.Claims.FirstOrDefault(x => x.Type == System.Security.Claims.ClaimTypes.Name).Value;
    MemberService service = new MemberService(token);
    Member m = await service.GetMember();
    
}
Impossible | 园豆:72 (初学一级) | 2018-05-23 12:34

@Impossible: 所有调用异步方法的同步方法都要改为异步的,可以看看这个博问: https://q.cnblogs.com/q/106342/

dudu | 园豆:30979 (高人七级) | 2018-05-23 13:05

@dudu: 最近在使用HttpClient的时候发现了另一个问题:Error while copying content to a stream。定位是var response = await _httpClient.SendAsync(request);抛出的异常。我没有使用response.EnsureSuccessStatusCode();,我这里有时还要用401和409的状态码。

Impossible | 园豆:72 (初学一级) | 2018-06-19 10:19
其他回答(4)
0

我知道,一定是代码中有什么问题才引起的。

爱编程的大叔 | 园豆:30839 (高人七级) | 2018-05-17 11:19
0

很明显有线程任务没有结束。

如果都不太熟.net core—— 那.net core有什么优势呢,为什么选.net core,何况乎还部署iis。

下有tcpListner,http Listner作为选择,上有wcf,asp.net族。

像web api,除非某些特定情况,一般不选择iis,更多是前三者,具体看情况。比如较复杂的关系业务类的,http Listner实现,过去盒子资源极度不足的且那会儿mono类库支持等问题使用tcp Listner,简单业务如单向游戏类的可能选择wcf,asp.net解决web api的话顶多现成asp.net项目需要开接口。

.net core更多的是个忽悠的噱头概念。比如从tcp、http写难道不能跨平台,iis本来都还相当于看门狗(或者专业点叫守护进程)[定时重启],能搞死只能是代码太烂——比如这种情况,情况通常有下:1,任务时间本身很长,2,循环死,3,面条线程死,4,递归调用死(类似第3条)。

花飘水流兮 | 园豆:13560 (专家六级) | 2018-05-17 12:24
0

进程dump一个下来,vs打开,分分钟那个就找到了原因了。

czd890 | 园豆:14412 (专家六级) | 2018-05-17 16:46
0

首先HttpClient应该是被注入Instance, 每次调用的时候设置从 HttpContextAccessor中获取 token(参考eShopOnContainers),

恰好遇到过这种问题,我的是因为部署在linux下,nginx header过长(不只是token,还有cookie)被截断导致的,治标的方法是去研究nginx的配置,治本的方式是在AddCookie(options => options.SessionStore 改成 CookieSessionStore),如果是分布式部署(多授权中心)方式,需要把CookieSessionStore的存储方式改成 Redis方式  

南昌炒粉 | 园豆:760 (小虾三级) | 2018-05-22 10:03

AddCookie中看到有 options.SessionStore,没CookieSessionStore,是要自己实现还是在某个命名空间中?

支持(0) 反对(0) Impossible | 园豆:72 (初学一级) | 2018-05-23 12:25

@Impossible: 自己根据实际情况实现

支持(0) 反对(0) 南昌炒粉 | 园豆:760 (小虾三级) | 2018-05-23 12:32

@Impossible: 解决了吗?解决了可以结帖啊,100分啊

支持(0) 反对(0) 南昌炒粉 | 园豆:760 (小虾三级) | 2018-05-28 08:42
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册