You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 12:20:40