如何将Process调用重构为HttpClient实现HTML文件翻译
重构建议:用HttpClient替代Process调用curl实现HTML翻译
问题背景
现有异步函数TranslateHTMLFileAsync通过调用curl命令完成HTML文件翻译,包含上传文档、轮询翻译状态、下载翻译结果三个核心步骤。目前仅下载步骤使用了HttpClient,需将上传和轮询部分也改用HttpClient重构,优化代码的可靠性与可维护性。
函数参数说明:
htmlfile:待翻译的HTML文件target_language:目标翻译语言checkOutTime:翻译处理超时时间(默认90秒)
核心重构点
1. 复用HttpClient实例
避免每次请求创建新的HttpClient,使用静态实例(或依赖注入管理),防止socket资源耗尽。
2. 替换文档上传的curl调用
用MultipartFormDataContent构造表单数据,对应curl的-F参数实现文件上传。
3. 替换状态轮询的curl调用
用FormUrlEncodedContent构造POST参数,对应curl的-d参数,替代Process调用。
4. 优化超时逻辑
用CancellationTokenSource实现精准超时控制,替代基于DateTime的判断。
5. 严谨错误处理
直接反序列化API响应,避免通过字符串包含判断结果,提升代码稳定性。
完整重构代码
首先补充CheckDocumentResponse类定义:
public class CheckDocumentResponse { public string status { get; set; } // 可根据API实际返回添加其他字段 }
重构后的TranslateHTMLFileAsync方法:
// 静态HttpClient实例,复用连接池 private static readonly HttpClient _httpClient = new HttpClient(); public static async Task<string> TranslateHTMLFileAsync(FileInfo htmlfile, Language target_language, int checkOutTime = 90) { var target_lang = target_language.ToString(); if (string.IsNullOrEmpty(target_lang)) throw new Exception("目标语言不支持"); if (!htmlfile.Extension.ToLowerInvariant().EndsWith(".htm") && !htmlfile.Extension.ToLowerInvariant().EndsWith(".html")) throw new Exception("提供的文件不是HTML格式"); string key = GlobalSetting.Get("APIKeys").StringValue; // 1. 上传文档 UploadDocumentResponse uploadResponse; using (var content = new MultipartFormDataContent()) { // 添加文件内容 using (var fileStream = htmlfile.OpenRead()) { var fileContent = new StreamContent(fileStream); content.Add(fileContent, "file", htmlfile.Name); } // 添加其他表单参数 content.Add(new StringContent(key), "auth_key"); content.Add(new StringContent(target_lang), "target_lang"); var uploadResponseMessage = await _httpClient.PostAsync("https://devapi.com/v2/document", content); uploadResponseMessage.EnsureSuccessStatusCode(); // 自动处理HTTP错误状态码 var uploadResponseBody = await uploadResponseMessage.Content.ReadAsStringAsync(); uploadResponse = Functions.DeserializeJSON<UploadDocumentResponse>(uploadResponseBody); if (uploadResponse == null || string.IsNullOrEmpty(uploadResponse.document_id)) throw new Exception($"文档上传失败,响应内容:{uploadResponseBody}"); } // 2. 轮询翻译状态 CheckDocumentResponse checkResponse; using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(checkOutTime)); await Task.Delay(5000, cts.Token); // 初始等待5秒 while (true) { await Task.Delay(1000, cts.Token); // 每次轮询间隔1秒 var checkFormContent = new FormUrlEncodedContent(new Dictionary<string, string> { { "auth_key", key }, { "document_key", uploadResponse.document_key } }); var checkResponseMessage = await _httpClient.PostAsync($"https://devapi.com/v2/document/{uploadResponse.document_id}", checkFormContent); checkResponseMessage.EnsureSuccessStatusCode(); var checkResponseBody = await checkResponseMessage.Content.ReadAsStringAsync(); checkResponse = Functions.DeserializeJSON<CheckDocumentResponse>(checkResponseBody); if (checkResponse == null || string.IsNullOrEmpty(checkResponse.status)) throw new Exception($"查询文档状态失败,响应内容:{checkResponseBody}"); if (checkResponse.status == "error") throw new Exception("文档翻译失败"); if (checkResponse.status == "done") break; } // 3. 下载翻译结果 var resultFormContent = new FormUrlEncodedContent(new Dictionary<string, string> { { "document_key", uploadResponse.document_key }, { "auth_key", key } }); var resultResponseMessage = await _httpClient.PostAsync($"https://devapi.com/v2/document/{uploadResponse.document_id}/result", resultFormContent); resultResponseMessage.EnsureSuccessStatusCode(); return await resultResponseMessage.Content.ReadAsStringAsync(); }
重构优势
- 性能提升:复用HttpClient连接池,减少TCP连接开销
- 可靠性增强:
EnsureSuccessStatusCode自动处理HTTP错误,CancellationToken精准控制超时 - 可维护性提升:统一使用HttpClient,避免Process调用的字符串拼接与平台依赖
- 错误处理更严谨:直接反序列化响应对象,避免字符串匹配的脆弱逻辑
内容的提问来源于stack exchange,提问作者user3920526
相关产品推荐
相关产品推荐

