使用Python调用Google Workspace API获取用户时遇400错误求助
Google Workspace Directory API调用返回HTTP 400 "Invalid Input"错误排查
问题描述
调用Google Workspace Directory API获取用户列表时收到HTTP 400错误,错误信息如下:
"exception": "googleapiclient.errors.HttpError: <HttpError 400 when requesting https://admin.googleapis.com/admin/directory/v1/users?customer=my_customer&query=isSuspended%3DFalse&maxResults=100&orderBy=email&viewType=admin_view&projection=basic&showDeleted=False&alt=json returned "Invalid Input". Details: "[{'message': 'Invalid Input', 'domain': 'global', 'reason': 'invalid'}]">"
使用的代码如下:
import frappe import json from google.oauth2 import service_account from googleapiclient.discovery import build SCOPES = ['https://www.googleapis.com/auth/admin.directory.user.readonly'] SUBJECT = 'workspace_email' CUSTOMER_ID = 'my_customer' @frappe.whitelist(allow_guest=True) def main(): credentials = service_account.Credentials.from_service_account_file( 'path_to_my_config.json', scopes=SCOPES ) credentials = credentials.with_subject(SUBJECT) admin = build('admin', 'directory_v1', credentials=credentials) results = admin.users().list( customer=CUSTOMER_ID, query='isSuspended=False', maxResults=100, orderBy='email', viewType='admin_view', projection='basic', showDeleted=False, ).execute() print(json.dumps(results, indent=4)) if __name__ == '__main__': main()
已尝试重新生成服务密钥,并为主体账号分配了Owner、Service Account Admin、Service Account Token Creator、Service Account User角色,仍无法解决问题。
解决方案
1. 核心问题:参数冲突
viewType和projection参数不能同时使用,这是触发"Invalid Input"错误的直接原因。根据Google Directory API规则:
- 指定
viewType=admin_view时,API会自动采用对应视图的默认数据投影规则,无需额外设置projection - 若要使用
projection参数筛选返回字段,必须移除viewType参数
2. 修正后的代码示例
方案一:保留projection=basic,移除viewType
import frappe import json from google.oauth2 import service_account from googleapiclient.discovery import build SCOPES = ['https://www.googleapis.com/auth/admin.directory.user.readonly'] SUBJECT = 'workspace_email' CUSTOMER_ID = 'my_customer' @frappe.whitelist(allow_guest=True) def main(): credentials = service_account.Credentials.from_service_account_file( 'path_to_my_config.json', scopes=SCOPES ) credentials = credentials.with_subject(SUBJECT) admin = build('admin', 'directory_v1', credentials=credentials) results = admin.users().list( customer=CUSTOMER_ID, query='isSuspended=False', maxResults=100, orderBy='email', projection='basic', showDeleted=False, ).execute() print(json.dumps(results, indent=4)) if __name__ == '__main__': main()
方案二:保留viewType=admin_view,移除projection
import frappe import json from google.oauth2 import service_account from googleapiclient.discovery import build SCOPES = ['https://www.googleapis.com/auth/admin.directory.user.readonly'] SUBJECT = 'workspace_email' CUSTOMER_ID = 'my_customer' @frappe.whitelist(allow_guest=True) def main(): credentials = service_account.Credentials.from_service_account_file( 'path_to_my_config.json', scopes=SCOPES ) credentials = credentials.with_subject(SUBJECT) admin = build('admin', 'directory_v1', credentials=credentials) results = admin.users().list( customer=CUSTOMER_ID, query='isSuspended=False', maxResults=100, orderBy='email', viewType='admin_view', showDeleted=False, ).execute() print(json.dumps(results, indent=4)) if __name__ == '__main__': main()
3. 额外检查项
- 确认
SUBJECT变量替换为实际的Google Workspace管理员邮箱(需拥有用户数据读取权限) - 检查服务账号是否已在Google Workspace管理控制台启用域范围委派,并授权了指定的
SCOPES权限
内容的提问来源于stack exchange,提问作者Verckys Orwa
相关产品推荐
相关产品推荐

