C#从URL加载并解析特殊格式JSON遇问题求助
嘿,我来帮你搞定这个问题!首先说下你用WebClient.DownloadString失败的事儿——这个类其实已经被.NET标记为过时了,现在更推荐用HttpClient来做HTTP请求,它不仅更灵活,还能更好地处理现代网络场景。另外,失败的原因可能有很多,比如网络权限问题、URL写错了、目标服务器返回错误状态码,我们可以通过捕获异常来精准排查。
接下来重点说解析你给出的JSON结构:{"Markets":[{"Label":"CHEESE/BTC","Name":"Cheese","Price":0.00000012,"Volume_24h":0.26702542,"Timestamp":1524662820}]},要解析这种结构化JSON,最稳妥的方式是先定义对应的实体类来映射它的结构。
步骤1:定义匹配的实体类
根据你的JSON结构,我们需要两个类:一个包含Markets数组的根类,和一个表示单个市场数据的类:
// 根类,对应整个JSON的最外层结构 public class MarketRoot { public List<Market> Markets { get; set; } } // 单个市场数据类,对应数组里的每一项 public class Market { public string Label { get; set; } public string Name { get; set; } public decimal Price { get; set; } // 因为JSON里的字段是Volume_24h,C#里习惯用驼峰命名,所以要加特性映射 [JsonProperty("Volume_24h")] // 如果你用Json.NET(Newtonsoft.Json)就用这个 // [JsonPropertyName("Volume_24h")] // 如果你用.NET自带的System.Text.Json就用这个 public decimal Volume24h { get; set; } public long Timestamp { get; set; } }
注意:如果用System.Text.Json(.NET Core 3.0+或.NET 5+自带),就用JsonPropertyName特性;如果用Json.NET(需要通过NuGet安装Newtonsoft.Json包),就用JsonProperty特性,别搞混了。
步骤2:用HttpClient获取并解析JSON
替代WebClient,我们用HttpClient来请求数据,同时处理可能的异常:
using System; using System.Net.Http; using System.Threading.Tasks; using Newtonsoft.Json; // 用Json.NET的话加这个 // using System.Text.Json; // 用System.Text.Json的话加这个 public class MarketFetcher { private readonly HttpClient _httpClient; public MarketFetcher() { _httpClient = new HttpClient(); // 可以设置请求超时,比如10秒 _httpClient.Timeout = TimeSpan.FromSeconds(10); } public async Task<MarketRoot> GetAndParseMarketData(string targetUrl) { try { // 发送GET请求拿到JSON字符串 string rawJson = await _httpClient.GetStringAsync(targetUrl); // 把JSON解析成我们定义的实体类 // Json.NET版本: MarketRoot marketData = JsonConvert.DeserializeObject<MarketRoot>(rawJson); // System.Text.Json版本: // MarketRoot marketData = JsonSerializer.Deserialize<MarketRoot>(rawJson); return marketData; } catch (HttpRequestException ex) { // 处理HTTP请求异常,比如网络断了、服务器404/500 Console.WriteLine($"请求出问题啦:{ex.Message}"); return null; } catch (JsonException ex) { // 处理JSON解析异常,比如格式不匹配 Console.WriteLine($"JSON解析失败:{ex.Message}"); return null; } } }
这里用异步方法是因为HTTP请求是IO操作,异步不会阻塞主线程,在桌面应用或Web应用里都更高效。
步骤3:调用并使用解析后的数据
你可以在代码里这样调用,拿到数据后就能随便用啦:
public static async Task Main(string[] args) { string yourTargetUrl = "这里填你的目标URL"; var fetcher = new MarketFetcher(); MarketRoot result = await fetcher.GetAndParseMarketData(yourTargetUrl); if (result != null && result.Markets != null && result.Markets.Count > 0) { var cheeseMarket = result.Markets[0]; Console.WriteLine($"交易对:{cheeseMarket.Label}"); Console.WriteLine($"名称:{cheeseMarket.Name}"); Console.WriteLine($"价格:{cheeseMarket.Price} BTC"); Console.WriteLine($"24小时成交量:{cheeseMarket.Volume24h}"); // 把Timestamp转换成可读的时间 DateTime updateTime = DateTimeOffset.FromUnixTimeSeconds(cheeseMarket.Timestamp).LocalDateTime; Console.WriteLine($"更新时间:{updateTime:yyyy-MM-dd HH:mm:ss}"); } }
如果你非要用WebClient的话...
如果你暂时不想换HttpClient,可以先排查WebClient.DownloadString失败的原因,通过捕获异常来看看具体问题:
try { using (WebClient client = new WebClient()) { // 有些服务器会校验User-Agent,可添加这个请求头 client.Headers.Add("User-Agent", "Mozilla/5.0"); string json = client.DownloadString("你的URL"); // 解析逻辑和上面一样,用JsonConvert或者JsonSerializer } } catch (WebException ex) { if (ex.Response is HttpWebResponse response) { Console.WriteLine($"服务器返回状态码:{(int)response.StatusCode} {response.StatusDescription}"); } Console.WriteLine($"错误详情:{ex.Message}"); }
常见的问题比如URL需要HTTPS但你写了HTTP,或者服务器需要特定的请求头,加个User-Agent往往能解决很多访问被拦截的问题。
内容的提问来源于stack exchange,提问作者Odacir Cristofolini

