调用Google Calendar API插入事件时提示‘缺少结束时间’问题求助
问题描述
使用服务账号域级代权代表域内用户插入Google Calendar事件时,返回「缺少结束时间」错误,但能正常获取该用户的日历数据。已尝试添加/移除calendarId、resource参数,以及调整start/end的时区配置,均无法解决问题。
原代码如下:
function testRequest(){ var service = getDWDS('Calendar: ', 'https://www.googleapis.com/auth/calendar', 'user@example.com'); var requestBody = { calendarId: "user@example.com", resource: { start: { dateTime: '2022-12-09T09:00:00Z', }, end: { dateTime: '2022-12-09T11:30:00Z', }, summary: "Test Request", conferenceData: { createRequest: { requestId: 'random' } }, } }; requestBody.headers = {'Authorization': 'Bearer ' + service.getAccessToken()}; requestBody.contentType = "application/json"; requestBody.method = "POST"; requestBody.muteHttpExceptions = false; var url = 'https://www.googleapis.com/calendar/v3/calendars/primary/events?conferenceDataVersion=1&sendUpdates=none'; Logger.log(requestBody) Logger.log(JSON.parse(UrlFetchApp.fetch(url, requestBody))) return JSON.parse(UrlFetchApp.fetch(url, requestBody)); } const OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY = "KEY GOES HERE" const OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL = 'SERVICE ACCOUNT EMAIL HERE'; function getDWDS(serviceName, scope, email) { // Logger.log('starting getDomainWideDelegationService for email: ' + email); return OAuth2.createService(serviceName + email) // Set the endpoint URL. .setTokenUrl('https://accounts.google.com/o/oauth2/token') // Set the private key and issuer. .setPrivateKey(OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY) .setIssuer(OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL) // Set the name of the user to impersonate. This will only work for // Google Apps for Work/EDU accounts whose admin has setup domain-wide // delegation: // https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority .setSubject(email) // Set the property store where authorized tokens should be persisted. .setPropertyStore(PropertiesService.getScriptProperties()) // Set the scope. This must match one of the scopes configured during the // setup of domain-wide delegation. .setScope(scope); }
问题分析与修复
核心错误点
- 请求体结构不符合API要求:
Google Calendar创建事件的POST接口,要求事件数据作为请求体的原始JSON内容传递,而非嵌套在resource字段中;同时calendarId需要放在URL路径里,不能放在请求体中。 - UrlFetchApp请求配置错误:
发送JSON类型POST请求时,需要将事件数据序列化为JSON字符串,通过payload字段传递,原代码未做这一步,导致API无法解析到正确的事件时间参数。
修正后的代码
function testRequest(){ const userEmail = "user@example.com"; const service = getDWDS('Calendar: ', 'https://www.googleapis.com/auth/calendar', userEmail); // 定义事件的核心数据 const eventData = { start: { dateTime: '2022-12-09T09:00:00Z', }, end: { dateTime: '2022-12-09T11:30:00Z', }, summary: "Test Request", conferenceData: { createRequest: { requestId: 'random' } }, }; // 配置UrlFetchApp请求参数 const requestConfig = { headers: {'Authorization': 'Bearer ' + service.getAccessToken()}, contentType: "application/json", method: "POST", muteHttpExceptions: false, payload: JSON.stringify(eventData) // 关键:将事件数据序列化为JSON字符串 }; // 把用户邮箱作为calendarId放入URL,或保留primary(代权后primary对应用户主日历) const url = `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(userEmail)}/events?conferenceDataVersion=1&sendUpdates=none`; try { const response = UrlFetchApp.fetch(url, requestConfig); const result = JSON.parse(response.getContentText()); Logger.log("事件创建成功:", result); return result; } catch(e) { Logger.log("请求错误:", e.toString()); throw e; } } const OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY = "KEY GOES HERE"; const OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL = 'SERVICE ACCOUNT EMAIL HERE'; function getDWDS(serviceName, scope, email) { return OAuth2.createService(serviceName + email) .setTokenUrl('https://accounts.google.com/o/oauth2/token') .setPrivateKey(OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY) .setIssuer(OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL) .setSubject(email) .setPropertyStore(PropertiesService.getScriptProperties()) .setScope(scope); }
关键修正说明
- 将事件数据与请求配置拆分,把事件数据通过
JSON.stringify转为字符串后放在payload字段,这是UrlFetchApp发送JSON POST请求的标准方式 - 将
calendarId移至URL路径中,符合Google Calendar API的参数传递规则 - 添加
encodeURIComponent处理用户邮箱,避免特殊字符导致URL解析失败 - 增加try-catch块,方便排查请求过程中的异常
内容的提问来源于stack exchange,提问作者JS Henney
相关产品推荐
相关产品推荐

