我怎么能不执行下载内容的GET请求?(How can I perform a GET request

2019-07-29 13:05发布

我工作的一个链接检查,一般我可以执行HEAD请求,然而,一些网站似乎禁用这个动词,所以失败我还需要执行一个GET请求(仔细检查链接是真的死了)

我用下面的代码作为我的链接测试仪:

public class ValidateResult
{
  public HttpStatusCode? StatusCode { get; set; }
  public Uri RedirectResult { get; set; }
  public WebExceptionStatus? WebExceptionStatus { get; set; }
}


public ValidateResult Validate(Uri uri, bool useHeadMethod = true, 
            bool enableKeepAlive = false, int timeoutSeconds = 30)
{
  ValidateResult result = new ValidateResult();

  HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
  if (useHeadMethod)
  {
    request.Method = "HEAD";
  }
  else
  {
    request.Method = "GET";
  }

  // always compress, if you get back a 404 from a HEAD it can be quite big.
  request.AutomaticDecompression = DecompressionMethods.GZip;
  request.AllowAutoRedirect = false;
  request.UserAgent = UserAgentString;
  request.Timeout = timeoutSeconds * 1000;
  request.KeepAlive = enableKeepAlive;

  HttpWebResponse response = null;
  try
  {
    response = request.GetResponse() as HttpWebResponse;

    result.StatusCode = response.StatusCode;
    if (response.StatusCode == HttpStatusCode.Redirect ||
      response.StatusCode == HttpStatusCode.MovedPermanently ||
      response.StatusCode == HttpStatusCode.SeeOther)
    {
      try
      {
        Uri targetUri = new Uri(Uri, response.Headers["Location"]);
        var scheme = targetUri.Scheme.ToLower();
        if (scheme == "http" || scheme == "https")
        {
          result.RedirectResult = targetUri;
        }
        else
        {
          // this little gem was born out of http://tinyurl.com/18r 
          // redirecting to about:blank
          result.StatusCode = HttpStatusCode.SwitchingProtocols;
          result.WebExceptionStatus = null;
        }
      }
      catch (UriFormatException)
      {
        // another gem... people sometimes redirect to http://nonsense:port/yay
        result.StatusCode = HttpStatusCode.SwitchingProtocols;
        result.WebExceptionStatus = WebExceptionStatus.NameResolutionFailure;
      }

    }
  }
  catch (WebException ex)
  {
    result.WebExceptionStatus = ex.Status;
    response = ex.Response as HttpWebResponse;
    if (response != null)
    {
      result.StatusCode = response.StatusCode;
    }
  }
  finally
  {
    if (response != null)
    {
      response.Close();
    }
  }

  return result;
}

这一切工作正常,很正常。 除了当我执行GET请求,整个有效载荷被下载(我在Wireshark中看到这个)。

有什么办法来配置底层ServicePointHttpWebRequest没有缓冲或急于负载响应主体呢?

(如果我是手工编写这一点,我将设置TCP接收窗口非常低,然后只抢到足够的数据包以获得接头,只要我有足够的信息停止ACKING TCP数据包。)

对于那些想知道这意味着实现,我不想下载一个40K的404,当我得到一个404,这样做了几十万次在网络上昂贵

Answer 1:

当你做一个GET,服务器将开始从文件末尾开始发送数据。 除非你打断它。 诚然,在10 MB /秒,这将是每秒兆字节,所以如果该文件是小,你会得到整个事情。 你可以尽量减少你实际下载几个方法的量。

首先,你可以调用request.Abort得到响应后调用之前response.close 。 这将保证底层的代码不尝试关闭响应之前下载整个事情。 这是否有助于对小文件,我不知道。 我不知道它会阻止你的应用程序挂时,它的尝试下载一个多GB的文件。

你可以做的另一件事是请求范围内,而不是整个文件。 见的AddRange方法及其重载。 你可以,例如,写request.AddRange(512)这将只下载前512个字节的文件。 这取决于,当然,服务器支持范围查询。 大多数做。 不过,大多数支持HEAD请求了。

你可能会最终不得不写试图在序列的东西的方法:

  • 尝试做一个HEAD请求。 如果这样的作品(即不返回500),那么你就大功告成了
  • 尝试用一个范围查询GET。 如果不返回500,那么你就大功告成了。
  • 做一个普通GET,具有request.AbortGetResponse回报。


Answer 2:

如果您使用的是GET请求,你会是否要或不接收消息体。 该数据仍然会被传输到您的端点,无论您是否从插座或没有看过。 这些数据将仅仅停留排队的RecvQ等待被选择出来。

对于这一点,你真的应该尽可能使用一个“HEAD”的要求,这将免去你的邮件正文。



Answer 3:

你不能使用Web客户端打开一个流和阅读只是你需要几个字节?

using (var client = new WebClient())
        {
            using (var stream = client.OpenRead(uri))
            {
                const int chunkSize = 100;
                var buffer = new byte[chunkSize];
                int bytesRead;
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    //check response here
                }
            }
        }

我不知道怎么打开的WebClient流内部。 但它似乎让数据的部分阅读。



文章来源: How can I perform a GET request without downloading the content?