莫名其妙的 C# HttpWebRequest.GetResponse() 超时错误

 

现象
现象:GET请求 “特定URL” 时超时,无法获取Response响应。代码阻塞在HttpWebRequest.GetResponse()里面。

注意是在访问 “特定URL” 时才超时,访问其他URL是正常的。例如,访问 http://hello.com/?page=2(以下称为page2)超时,而访问 http://hello.com/?page=1 (以下称为page1)和 http://hello.com/?page=3 (以下称为page3)却是正常的。访问page1、page3每次都成功,访问page2每次都超时。

然而page2是可以被浏览器正常访问的;我用易语言两种方法GET请求page2都正常。排除了目标网站不工作或限制访问的情况。

分析
我的C#程序启动后第一次请求就是访问page2,排除了Connection、Request、Response等资源耗尽的情况。

网上有说.Net 3.5 / 4 默认使用代理,加上 HttpWebRequest.Proxy = null; 后也不行。

不是超时设定过短的问题,默认的100秒绝对不短。

我怀疑.Net库有BUG,把 .Net 2.0 换成了.Net 4.5.2、4.6.1,还是不行。

因超时而触发的异常对象只是说超时了,没有更多有价值的参考信息。

网络上找到的下面这篇经典文章,提供了不少解决GetResponse超时问题的办法,但不适用于我现在遇到的状况。

【已解决】HttpWebRequest的GetResponse或GetRequestStream偶尔超时 + 总结各种超时死掉的可能和相应的解决办法

一定是哪里出了问题!问题是出在哪里?

解决
问题解决了。

事实证明还是目标网站的page2有些特殊。经过Fidder观测,发现第一次访问page2时被302重定向到认证页面,进而又被302重定向到page2,我发现必须在访问认证页面时接收Cookie并将其传入到第二次访问page2的请求中。访问page1、page3等其他页面并不需要这一步骤。

上文提到的易语言的两个办法,“HTTP读文件()” 和 “网页_访问_对象()” 都自动处理了Cookie,不需要我关心,自己就工作的很好。可是C#代码的WEB请求并没有帮我接收和传递Cookie,导致最后302重定向很多遍之后以超时告终。

最后的解决办法是,我自行编码跟踪302重定向,接收Cookie并传递给下一个请求。以下是相关C#代码。

// 跟踪302临时跳转,接收Cookies并传递给下一次请求。
// by Liigo 20170303
public static string GetHtmlExX(string strUrl, string strReferer, string strCookies)
{
    try
    {
        HttpWebRequest req;
        HttpWebResponse res = GetHttpWebResponseNoRedirect(strUrl, strReferer, strCookies, out req);
        while (res.StatusCode == HttpStatusCode.Found)
        {
            strUrl = res.Headers[HttpResponseHeader.Location];
            strCookies = res.Headers[HttpResponseHeader.SetCookie];
            res.Close();
            req.Abort();
            res = GetHttpWebResponseNoRedirect(strUrl, strReferer, strCookies, out req);
        }
        Stream responseStream = res.GetResponseStream();
        StreamReader streamReader = new StreamReader(responseStream);
        string html = streamReader.ReadToEnd();
        streamReader.Close();
        responseStream.Close();
        res.Close();
        req.Abort();
        return html;
    } catch (Exception e)
    {
        string msg = e.Message;
        return "";
    }
}

// 执行HTTP GET请求,返回Response对象和Request对象。调用者负责关闭他们:Response.Close(),Request.Abort()。
public static HttpWebResponse GetHttpWebResponseNoRedirect(string strUrl, string strReferer, string strCookies, out HttpWebRequest request)
{
    HttpWebRequest req = null;
    try
    {
        req = HttpWebRequest.Create(strUrl) as HttpWebRequest;
        if (!string.IsNullOrEmpty(strCookies))
            req.Headers[HttpRequestHeader.Cookie] = strCookies;
        req.ContentType = contentType;
        req.ServicePoint.ConnectionLimit = maxTry;
        if (!string.IsNullOrEmpty(strReferer))
            req.Referer = strReferer;
        req.Accept = accept;
        req.UserAgent = userAgent;
        req.Method = "GET";
        req.Timeout = 15000;
        req.AllowAutoRedirect = false;
        HttpWebResponse res = req.GetResponse() as HttpWebResponse;
        request = req; // Liigo: 如果此处调用req.Abort()关闭请求,则返回的Response对象的数据流是不可读的("流不可读")。
        return res;
    }
    catch
    {
        if (req != null) req.Abort();
        request = null;
        return null;
    }
}
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
public static T Post<T>(string url, string data, string staffId, string contentType) { try { byte[] bytes = Encoding.UTF8.GetBytes(data); HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url); string timeStamp = ApiHelper.GetTimeStamp(); string random = ApiHelper.GetRandom(); httpWebRequest.Headers.Add("staffid", staffId.ToString()); httpWebRequest.Headers.Add("timestamp", timeStamp); httpWebRequest.Headers.Add("nonce", random); //ResultMsg signToken = ApiHelper.GetToken(url, staffId); // httpWebRequest.Headers.Add("signature", ApiHelper.GetSignature(timeStamp, random, staffId, data, signToken)); httpWebRequest.Headers.Add("jwtcookie", GetJwt(url, data));//cwj 直接通过jwt验证身份 httpWebRequest.Method = "POST"; httpWebRequest.ContentLength = (long)bytes.Length; httpWebRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"; httpWebRequest.ContentType = contentType; Stream requestStream = httpWebRequest.GetRequestStream(); requestStream.Write(bytes, 0, bytes.Length); httpWebRequest.Timeout = 300000; httpWebRequest.Headers.Set("Pragma", "no-cache"); HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); Stream responseStream = httpWebResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8); string text = streamReader.ReadToEnd(); requestStream.Close(); streamReader.Close(); responseStream.Close(); httpWebRequest.Abort(); httpWebResponse.Close(); return JsonConvert.DeserializeObject<T>(text); } catch (Exception) { throw; } }
06-08

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值