简体   繁体   English

不带Fiddler(Http / Https调试器)的第二次GetAsync尝试,带有ResponseHeadersRead的HttpClient失败(超时)

[英]HttpClient with ResponseHeadersRead fails(timeouts) at 2nd GetAsync try without Fiddler(Http/Https debugger)

I'm trying to get some page's status code. 我正在尝试获取某些页面的状态码。

Problem is default GetAsync method returns the whole page with content, while I only needed the header to check page's status(404,403, etc..), which will end up as hogging up the memory since I have to check tons of URIs. 问题是默认的GetAsync方法返回整个页面的内容,而我只需要标题即可检查页面的状态(404,403,等等。),由于我必须检查大量的URI,最终会占用大量内存。

I added ResponseHeadersRead option to solve that memory hogging issue, but then that code started to throw "A Task was cancelled" Exception, which means timeout. 我添加了ResponseHeadersRead选项来解决该内存占用问题,但随后该代码开始引发“任务已取消”异常,这意味着超时。

Things that i know : 我知道的事情:

  1. ResponseHeadersRead code ONLY works, when i runs fiddler(Http/Https Debugger) on my local PC. 当我在本地PC上运行fiddler(Http / Https Debugger)时,ResponseHeadersRead代码仅适用。

  2. ResponseHeadersRead code works at online-coding environment, like dotnetfiddle. ResponseHeadersRead代码可在在线编码环境(例如dotnetfiddle)下工作。 but doesnt work on Windows OS Environment. 但不适用于Windows OS环境。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Security.Cryptography;


public class Program
{
    public static string[] Tags = { "first", "second" };
    public static string prefix = null;
    static HttpClient Client = new HttpClient();
    public static void Main()
    {
        System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
        Client.DefaultRequestHeaders.ConnectionClose = true;

        // limit parallel thread
        Parallel.ForEach(Tags,
        new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 1.0)) },
        tag =>
        {
            for (int i = 1; i < 4; i++)
            {
                switch (i)
                {
                    case 1:
                        prefix = "1";
                        break;
                    case 2:
                        prefix = "2";
                        break;
                    case 3:
                        prefix = "3";
                        break;
                }
                Console.WriteLine(tag.ToString() + " and " + i);
                HttpResponseMessage response = Client.GetAsync("https://example.com/" + prefix).Result; // this works
//                HttpResponseMessage response = Client.GetAsync("https://example.com/" + prefix,HttpCompletionOption.ResponseHeadersRead).Result; // this fails from 2nd try with one url.
                Console.WriteLine(i + " and " + (int)response.StatusCode);
                if (response.StatusCode != HttpStatusCode.NotFound)
                {

                }

            }
        });

    }
}

It gets thread timeout with ResponseHeadersRead, while it isn't without it. 它不是通过使用ResponseHeadersRead来获取线程超时的,而是没有使用它。

在此处输入图片说明

When you set ResponseHeadersRead, you are instructing the HTTP client to read only the HTTP headers from each response, and so the TCP/IP connection on which the request is made is in the middle of the response until you read the response body. 设置ResponseHeadersRead时,您将指示HTTP客户端仅读取每个响应中的HTTP标头,因此,在您读取响应正文之前,发出请求的TCP / IP连接位于响应的中间。

And there's a limit to how many connections HttpClient will open to any particular web site. HttpClient可以打开到任何特定网站的连接数是有限制的 This defaults to 2. So you open two connections, and try to open a third, which blocks waiting for an available connection. 默认值为2。因此,您打开两个连接,然后尝试打开第三个连接,这将阻止等待可用的连接。

You can simply increase the connection limit for your application. 您可以简单地增加应用程序的连接限制。

eg: 例如:

ServicePointManager.DefaultConnectionLimit = 10;

Don't use Parallel for async code, it is intended for CPU bound. 不要将Parallel用于async代码,它用于CPU绑定。 You can run all the requests concurrently without wasting threads blocking on it. 您可以同时运行所有请求,而不会浪费线程阻塞它。 The way to solve this issue is not to increase DefaultConnectionLimit , however, this will solve it in this case. 解决此问题的方法是不增加DefaultConnectionLimit ,但是,在这种情况下可以解决此问题。 The correct way to deal with ResponseHeadersRead is to either Dispose the response ie 处理ResponseHeadersRead的正确方法是Dispose response

using(HttpResponseMessage response = Client.GetAsync("https://example.com/" + prefix, HttpCompletionOption.ResponseHeadersRead).Result) {}

or to read the Content of the response. 或阅读回复的Content

var data = response.ReadAsStringAsync().Result;

With ResponseHeadersRead , you need to do this in order for the connection to be closed. 使用ResponseHeadersRead ,您需要执行此操作才能关闭连接。 I would encourage you to rewrite this code to get rid of Parallel and not to call .Result on your async calls. 我鼓励您重写此代码以摆脱Parallel而不要在async调用中调用.Result

You can do something like this: 您可以执行以下操作:

private static async Task Go()
{
    System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
    Client.DefaultRequestHeaders.ConnectionClose = true;

    var tasks = Tags.Select(tag =>
    {
        var requests = new List<Task>();
        for (int i = 1; i < 4; i++)
        {
            switch (i)
            {
                case 1:
                    prefix = "1";
                    break;
                case 2:
                    prefix = "2";
                    break;
                case 3:
                    prefix = "3";
                    break;
            }

            requests.Add(MakeRequest(Client, prefix, tag));
        }
        return requests;
    }).SelectMany(t => t);

    await Task.WhenAll(tasks);
}

private async static Task MakeRequest(HttpClient client, string prefix, string tag)
{

    using (var response = await client.GetAsync("https://example.com/" + prefix, HttpCompletionOption.ResponseHeadersRead))
    {
        Console.WriteLine(tag + " and " + prefix);
        Console.WriteLine(prefix + " and " + (int)response.StatusCode);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM