使用.NET版Google Calendar API批量请求异常处理问题咨询
.NET Google Calendar API批量请求错误定位方案
当使用.NET版Google Calendar API的批量请求功能时,只要其中某条请求(比如传入错误的eventId)出现问题,整个批量请求会直接抛出异常,预先设置的回调函数完全不会触发,根本没法定位到底是哪个事件出错。
比如这段官方示例代码,当eventId无效时,ExecuteAsync()会直接抛异常,回调里的代码永远不会执行:
UserCredential credential; using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read)) { credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( GoogleClientSecrets.Load(stream).Secrets, new[] { CalendarService.Scope.Calendar }, "user", CancellationToken.None, new FileDataStore("Calendar.Sample.Store")); } // Create the service. var service = new CalendarService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = "Google Calendar API Sample", }); // Create a batch request. var request = new BatchRequest(service); var eventId = "***Bad event id***"; request.Queue<Event>(service.Events.Update( new Event { Summary = "Learn how to execute a batch request", Start = new EventDateTime() { DateTime = new DateTime(2014, 1, 1, 10, 0, 0) }, End = new EventDateTime() { DateTime = new DateTime(2014, 1, 1, 12, 0, 0) } }, calendar.Id, eventId), (content, error, i, message) => { // This is never called!!! }); await request.ExecuteAsync();
解决办法
1. 捕获异常并手动解析批量响应
ExecuteAsync()抛出的GoogleApiException里包含了完整的批量响应内容,我们可以捕获这个异常,拆分响应内容逐个检查每个请求的结果:
try { await request.ExecuteAsync(); } catch (GoogleApiException ex) { // 提取批量响应的分隔符 var boundary = ex.Headers.ContentType.Parameters.First(p => p.Name == "boundary").Value; // 拆分响应为单个请求结果 var responseParts = ex.ResponseContent.Split(new[] { $"--{boundary}" }, StringSplitOptions.RemoveEmptyEntries); foreach (var part in responseParts) { // 跳过结束标记 if (part.TrimEnd().EndsWith("--")) continue; // 解析状态码 var statusLineIndex = part.IndexOf("HTTP/1.1", StringComparison.Ordinal); if (statusLineIndex == -1) continue; var statusLineEnd = part.IndexOf("\r\n", statusLineIndex, StringComparison.Ordinal); var statusCode = int.Parse(part.Substring(statusLineIndex, statusLineEnd - statusLineIndex).Split(' ')[1]); if (statusCode >= 400) { // 提取请求ID(对应Queue时传入的自定义标识) var contentIdIndex = part.IndexOf("Content-ID: ", StringComparison.Ordinal); var contentIdEnd = part.IndexOf("\r\n", contentIdIndex, StringComparison.Ordinal); var requestId = part.Substring(contentIdIndex + 11, contentIdEnd - (contentIdIndex + 11)); // 提取错误信息 var errorJsonStart = part.IndexOf("{", StringComparison.Ordinal); var errorJsonEnd = part.LastIndexOf("}", StringComparison.Ordinal) + 1; var errorDetails = JsonConvert.DeserializeObject<GoogleApiError>(part.Substring(errorJsonStart, errorJsonEnd - errorJsonStart)); Console.WriteLine($"请求 {requestId} 失败,状态码 {statusCode}:{errorDetails.Error.Message}"); } } }
需要先定义用于反序列化错误的类:
public class GoogleApiError { public ErrorDetail Error { get; set; } } public class ErrorDetail { public string Message { get; set; } public string Code { get; set; } }
2. 给每个请求添加自定义标识
在调用Queue方法时,传入自定义的请求ID(比如用事件ID当标识),这样解析时能直接对应到具体事件:
// 用eventId作为自定义请求标识 request.Queue<Event>( service.Events.Update(new Event { ... }, calendar.Id, eventId), (content, error, i, message) => { /* 正常回调逻辑 */ }, eventId);
这样在解析响应的Content-ID时,就能直接拿到这个eventId,精准定位出错的事件。
总结
通过捕获GoogleApiException并手动解析批量响应内容,再配合自定义请求标识,就能在批量请求部分失败时,准确找到出错的事件,不用再因为整批失败而无从排查。
内容的提问来源于stack exchange,提问作者Craig
相关产品推荐
相关产品推荐

