ASP.NET中GetStringAsync偶现返回Null及流式读取咨询
问题:流式航班数据获取时API响应超时返回Null,Postman测试正常
我尝试从流式数据源获取航班数据,该数据最终文件大小约10MB+,有时获取耗时超1分钟。以下控制器代码可正常运行,但当API响应耗时较长时返回结果为Null,而Postman测试相同请求未出现此问题。请问我的代码是否存在问题?是否支持流式读取逐步获取数据?
private async Task<List<Model>> GetFlightData() { using (var client = new HttpClient()) { var content = await client.GetStringAsync("http://api.travelpayouts.com/v1/flight_search_results?uuid=" + flightSearchID); var result = JsonConvert.DeserializeObject<List<Model>>(content); return result; } }
分析与解决方案
1. 当前代码的核心问题
你的代码确实存在两个关键问题,导致长耗时请求返回Null:
- 一次性加载全量数据:
GetStringAsync会把整个10MB+的响应内容直接加载到内存里,不仅占用内存,一旦请求超时就会触发未捕获的异常,最终导致方法返回Null。 - 超时设置不匹配:
HttpClient默认超时是100秒,你的请求有时超过1分钟(60秒),接近甚至超过这个阈值就容易被取消;而Postman默认超时通常是5分钟,所以不会触发这个问题。
2. 实现流式读取的优化方案
想要支持流式读取、避免超时问题,我们可以调整代码逻辑,分步骤处理响应:
方案一:基础优化(调整超时+流式反序列化)
这个方案既解决超时问题,又不用一次性加载全量数据到内存:
private async Task<List<Model>> GetFlightData() { using (var client = new HttpClient()) { // 把超时时间调到5分钟,根据你的实际需求调整 client.Timeout = TimeSpan.FromMinutes(5); // 使用ResponseHeadersRead选项,拿到响应头就开始读内容,不用等全量下载完 using (var response = await client.GetAsync( $"http://api.travelpayouts.com/v1/flight_search_results?uuid={flightSearchID}", HttpCompletionOption.ResponseHeadersRead)) { // 先确保API返回成功,避免无效响应 response.EnsureSuccessStatusCode(); // 流式读取内容并逐步反序列化 using (var stream = await response.Content.ReadAsStreamAsync()) using (var reader = new StreamReader(stream)) using (var jsonReader = new JsonTextReader(reader)) { var serializer = new JsonSerializer(); return serializer.Deserialize<List<Model>>(jsonReader); } } } }
方案二:添加异常捕获(方便排查问题)
加上异常捕获,能明确知道请求失败的原因,避免莫名其妙返回Null:
private async Task<List<Model>> GetFlightData() { try { using (var client = new HttpClient()) { client.Timeout = TimeSpan.FromMinutes(5); using (var response = await client.GetAsync( $"http://api.travelpayouts.com/v1/flight_search_results?uuid={flightSearchID}", HttpCompletionOption.ResponseHeadersRead)) { response.EnsureSuccessStatusCode(); using (var stream = await response.Content.ReadAsStreamAsync()) using (var reader = new StreamReader(stream)) using (var jsonReader = new JsonTextReader(reader)) { var serializer = new JsonSerializer(); return serializer.Deserialize<List<Model>>(jsonReader); } } } } catch (Exception ex) { // 这里可以换成你的日志组件,记录异常详情 Console.WriteLine($"获取航班数据出错:{ex.Message}\n{ex.StackTrace}"); // 根据业务需求返回空列表或者null,建议返回空列表更安全 return new List<Model>(); } }
3. 额外建议
- 复用HttpClient实例:每次创建新的
HttpClient会消耗Socket资源,建议用单例或者依赖注入的方式复用一个实例。 - 检查API限流:如果频繁超时,也可能是API对请求频率有限制,可以查看API文档确认。
内容的提问来源于stack exchange,提问作者Jad
相关产品推荐
相关产品推荐

