基于HttpClient调用文件转换API时,如何仅返回status为successful的响应结果
Absolutely! You can add retry logic and status validation to your HttpClient call to only return the response when the status field is successful. Here's a robust implementation tailored to your scenario:
The core idea is to check the status field in the response, retry when it's converting, and only return the result once it's marked successful. We'll also add safeguards to avoid infinite loops and improve reliability.
Step 1: Define Strongly-Typed Response Models
First, create C# classes to map the API response structure—this is far more maintainable than parsing raw JSON:
public class ConversionResponse { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("key")] public string ApiKey { get; set; } [JsonPropertyName("status")] public string Status { get; set; } [JsonPropertyName("sandbox")] public bool IsSandbox { get; set; } [JsonPropertyName("created_at")] public DateTime CreatedAt { get; set; } [JsonPropertyName("finished_at")] public DateTime FinishedAt { get; set; } [JsonPropertyName("source_file")] public FileDetails SourceFile { get; set; } [JsonPropertyName("target_files")] public List<FileDetails> TargetFiles { get; set; } [JsonPropertyName("target_format")] public string TargetFormat { get; set; } [JsonPropertyName("credit_cost")] public int CreditCost { get; set; } } public class FileDetails { [JsonPropertyName("id")] public int Id { get; set; } [JsonPropertyName("name")] public string Name { get; set; } [JsonPropertyName("size")] public int Size { get; set; } }
Step 2: Implement the Retry-Aware API Call
Modify your original code to include status checks and retry logic with reasonable limits:
// Configure these values based on your API's typical conversion speed private const int MaxRetryAttempts = 25; private const int RetryDelayMs = 4000; // Wait 4 seconds between retries public async Task<ConversionResponse> GetCompletedConversionResult(string apiUrl, string apiKey) { // Reuse HttpClient (better practice than creating a new one each time) using var handler = new HttpClientHandler { Credentials = new NetworkCredential(apiKey, "") }; using var client = new HttpClient(handler); client.Timeout = TimeSpan.FromSeconds(75); // Avoid infinite timeouts for (int attempt = 0; attempt < MaxRetryAttempts; attempt++) { var request = new HttpRequestMessage(HttpMethod.Get, apiUrl); using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); // First, ensure the HTTP request itself succeeded response.EnsureSuccessStatusCode(); // Read and parse the response using var responseStream = await response.Content.ReadAsStreamAsync(); using var reader = new StreamReader(responseStream); var jsonContent = await reader.ReadToEndAsync(); var conversionResult = JsonSerializer.Deserialize<ConversionResponse>(jsonContent); // Handle different statuses if (conversionResult?.Status.Equals("successful", StringComparison.OrdinalIgnoreCase) == true) { // Optional: Validate target files exist as expected if (conversionResult.TargetFiles?.Any(file => !string.IsNullOrEmpty(file.Name)) != true) { throw new InvalidOperationException("Conversion marked successful but no valid target files found."); } return conversionResult; } else if (conversionResult?.Status.Equals("converting", StringComparison.OrdinalIgnoreCase) == true) { // Still converting—wait and retry await Task.Delay(RetryDelayMs); continue; } else { // Handle unexpected statuses (e.g., "failed") throw new InvalidOperationException($"Conversion failed with status: {conversionResult?.Status ?? "unknown"}"); } } // Exceeded max retries without success throw new TimeoutException($"Conversion did not complete after {MaxRetryAttempts} attempts."); }
Key Improvements & Notes
- Strongly-Typed Parsing: Avoids messy raw JSON handling and catches typos at compile time.
- Controlled Retries: Limits the number of attempts and adds a delay to avoid overwhelming the API. Adjust
MaxRetryAttemptsandRetryDelayMsbased on how long your files typically take to convert. - Safe HttpClient Usage: While we use
usinghere for simplicity, in production consider usingIHttpClientFactoryto reuse HttpClient instances and prevent socket exhaustion. - Timeout Protection: Replaces
Timeout.Infinitewith a reasonable timeout to prevent hanging requests. - Explicit Error Handling: Throws clear exceptions for failed conversions or missing files, making it easier to debug upstream issues.
Bonus Tip
If the API supports webhooks, consider using that instead of polling. You can register a webhook URL with the API, and it will send a notification when the conversion completes—this is more efficient than repeated GET requests.
内容的提问来源于stack exchange,提问作者Matteo Pietro Peru

