簡體   English   中英

不帶Fiddler(Http / Https調試器)的第二次GetAsync嘗試,帶有ResponseHeadersRead的HttpClient失敗(超時)

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

我正在嘗試獲取某些頁面的狀態碼。

問題是默認的GetAsync方法返回整個頁面的內容,而我只需要標題即可檢查頁面的狀態(404,403,等等。),由於我必須檢查大量的URI,最終會占用大量內存。

我添加了ResponseHeadersRead選項來解決該內存占用問題,但隨后該代碼開始引發“任務已取消”異常,這意味着超時。

我知道的事情:

  1. 當我在本地PC上運行fiddler(Http / Https Debugger)時,ResponseHeadersRead代碼僅適用。

  2. ResponseHeadersRead代碼可在在線編碼環境(例如dotnetfiddle)下工作。 但不適用於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)
                {

                }

            }
        });

    }
}

它不是通過使用ResponseHeadersRead來獲取線程超時的,而是沒有使用它。

在此處輸入圖片說明

設置ResponseHeadersRead時,您將指示HTTP客戶端僅讀取每個響應中的HTTP標頭,因此,在您讀取響應正文之前,發出請求的TCP / IP連接位於響應的中間。

HttpClient可以打開到任何特定網站的連接數是有限制的 默認值為2。因此,您打開兩個連接,然后嘗試打開第三個連接,這將阻止等待可用的連接。

您可以簡單地增加應用程序的連接限制。

例如:

ServicePointManager.DefaultConnectionLimit = 10;

不要將Parallel用於async代碼,它用於CPU綁定。 您可以同時運行所有請求,而不會浪費線程阻塞它。 解決此問題的方法是不增加DefaultConnectionLimit ,但是,在這種情況下可以解決此問題。 處理ResponseHeadersRead的正確方法是Dispose response

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

或閱讀回復的Content

var data = response.ReadAsStringAsync().Result;

使用ResponseHeadersRead ,您需要執行此操作才能關閉連接。 我鼓勵您重寫此代碼以擺脫Parallel而不要在async調用中調用.Result

您可以執行以下操作:

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