异步HTTP请求返回状态码0:Web解析应用异步实现故障排查
问题分析
异步调用时RestResponse状态码始终为0,同步阻塞调用正常,核心原因大概率是异步请求过程中出现了未被捕获的异常(被吞),或者异步场景下请求未正确完成(如代理失效、响应属性未正确填充),导致循环结束后返回的是未正确初始化的RestResponse(默认状态码为0)。
解决方案步骤
1. 先排查异常原因:停止吞异常
当前TryGetAsync的catch块直接吞了所有异常,无法定位异步请求失败的具体原因。修改代码添加日志输出:
public async Task<RestResponse?> TryGetAsync(Uri uri, Predicate<RestResponse> condition, int tryCount = 15, List<KeyValuePair<string, string>> query = null, List<KeyValuePair<string, string>> headers = null, Method method = Method.Get, string body = null) { WebClient? client = null; RestResponse? res = null; for(int i = 0; i < tryCount; i++) { try { client = new WebClient(source.Invoke(serviceName), serviceName, timeout); res = await client.GetResponseAsync(uri, query, headers, method, body); // 新增:打印响应状态,排查condition是否生效 Console.WriteLine($"第{i+1}次请求:状态码={res.StatusCode}, IsSuccessStatusCode={res.IsSuccessStatusCode}, IsSuccessful={res.IsSuccessful}"); if (condition(res)) return res; } catch(Exception ex) { // 新增:打印异常细节 Console.WriteLine($"第{i+1}次请求失败:{ex.Message}\n堆栈:{ex.StackTrace}"); } finally { if (client != null) { client.SetCDToProxy(new TimeSpan(cd)); client.Dispose(); } } } return res; }
运行异步代码后,查看控制台输出,就能知道每次请求是失败(异常原因)还是响应不满足condition条件。
2. 验证WebClient.GetResponseAsync的异步实现
检查WebClient.GetResponseAsync方法,确保它在异步模式下:
- 正确填充
RestResponse的StatusCode、IsSuccessStatusCode等核心属性 - 不会因为异步上下文问题导致响应未完全接收就返回
如果该方法是基于RestSharp的异步封装,确保调用的是RestSharp官方的异步API(如ExecuteAsync),而非自行实现的半异步逻辑。
3. 检查代理获取的线程安全性
确认ProxyProvider.GetCoreNoCD(name)方法是线程安全的:
- 异步场景下会并发调用该方法,如果内部有共享资源(如代理池)且未做线程同步,可能获取到无效/已被占用的代理,导致请求失败
- 若存在线程安全问题,需添加锁或改用线程安全的代理池实现
4. 优化异步代码写法(非核心,但更规范)
将异步版本的GetTableAsync改为更简洁的写法,同时增加空值判断:
private static async Task<HtmlNode> GetTableAsync(int page) { ProxyClient client = new ProxyClient((name) => ProxyProvider.GetCoreNoCD(name), serviceName, 10000, 10000); var response = await client.TryGetAsync( new Uri(GetPageUrl(page)), res => res.IsSuccessStatusCode && res.IsSuccessful, 5 ); if (response == null) { throw new InvalidOperationException("5次请求尝试均未成功"); } HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(response.Content); return doc.DocumentNode.SelectSingleNode("//div[@class=\"table_block\"]/table"); }
5. 排查IsSuccessful自定义属性
如果IsSuccessful是你自定义的属性,而非RestSharp原生属性,需确保在异步请求完成后该属性被正确赋值。比如同步请求时可能同步处理了响应内容设置该属性,但异步时遗漏了这一步。
内容的提问来源于stack exchange,提问作者opadfnezig
相关产品推荐
相关产品推荐

