Swift应用更新Google Sheets遇401/404/405错误,求认证指导
解决Swift应用更新Google Sheets时的认证与请求错误问题
问题概述
开发Swift应用更新Google Sheets一行三列(“Name”、整数、日期)内容时,遇到以下问题:
- 当前返回401“UNAUTHENTICATED”和“CREDENTIALS_MISSING”错误
- 此前出现过404、405错误
- 创建了未关联Google Console项目的公开可编辑Google Sheets,不清楚正确认证方式
问题分析与修复步骤
1. 认证逻辑错误:公开表格仍需合法凭证
即便表格设为公开可编辑,通过Google Sheets API修改内容仍需API密钥或OAuth 2.0认证,直接发送未认证请求必然触发401错误。同时你的代码引入了多个认证库但未完成认证流程,导致请求无有效凭证。
2. 请求端点与HTTP方法错误
- 404错误原因:
spreadsheetId末尾多了斜杠/,导致URL无效,正确的ID应为纯字符串,无后缀符号。 - 405错误原因:使用了
PUT方法但调用了错误的端点,Sheets API的更新端点应为https://sheets.googleapis.com/v4/spreadsheets/{spreadsheetId}/values/{range},而非docs.google.com域名下的URL。
3. 请求参数与格式错误
- 错误设置
Content-Type: application/x-www-form-urlencoded,Sheets API要求JSON格式,需改为application/json。 - 参数结构错误:更新单个范围时,只需传递
{"values": [[值1, 值2, 值3]]},无需额外嵌套range字段;且Date.self会输出类型字符串,应生成实际日期格式(如ISO8601字符串)。
修复后的代码示例
步骤1:简化Podfile(移除冗余依赖)
保留核心库即可,避免认证库冲突:
platform :ios, '16.0' target 'MyApp' do use_frameworks! # 核心依赖 pod 'GoogleAPIClientForREST/Sheets' pod 'GTMAppAuth' pod 'Alamofire' # 若使用Google官方SDK可移除 target 'MyAppTests' do inherit! :search_paths end target 'MyAppUITests' do inherit! :search_paths end end
步骤2:使用Google官方SDK完成认证与更新
推荐用GoogleAPIClientForREST处理认证和请求,避免手动拼接URL出错:
import UIKit import GoogleAPIClientForREST import GTMAppAuth class ViewController3: UIViewController { private let scopes = [kGTLRAuthScopeSheetsSpreadsheets] private let service = GTLRSheetsService() // 替换为你的spreadsheetId(去掉末尾斜杠) private let spreadsheetId = "121212121212121212121212121212121212" private let range = "BlueBook!A3:C3" override func viewDidLoad() { super.viewDidLoad() // 先完成认证流程 authenticate() } // OAuth 2.0认证流程 private func authenticate() { guard let clientID = "YOUR_GOOGLE_CONSOLE_CLIENT_ID" else { return } let config = GTMAppAuthFetcherAuthorization.configuration( clientID: clientID, scopes: scopes ) GTMAppAuthFetcherAuthorization.authorize( with: config, presenting: self ) { [weak self] auth, error in guard let auth = auth, error == nil else { print("认证失败:\(error?.localizedDescription ?? "未知错误")") return } self?.service.authorizer = auth // 认证成功后执行更新 self?.updateSheet() } } // 更新Google Sheets数据 private func updateSheet() { // 构造更新数据:[Name, 整数, 日期] let dateFormatter = ISO8601DateFormatter() let dateString = dateFormatter.string(from: Date()) let values = [["TestName", 50, dateString]] // 创建API请求 let request = GTLRSheetsQuery_SpreadsheetsValuesUpdate.query( withObject: GTLRSheets_ValueRange.init(values: values), spreadsheetId: spreadsheetId, range: range ) request.valueInputOption = "RAW" // 按原始值写入 // 发送请求 service.executeQuery(request) { _, result, error in if let error = error { print("更新失败:\(error.localizedDescription)") return } print("更新成功!") } } }
步骤3:Google Console配置(必填)
- 前往Google Console创建项目,启用Google Sheets API。
- 创建iOS类型的OAuth 2.0客户端ID,填写应用Bundle ID。
- 将生成的客户端ID替换到代码中的
YOUR_GOOGLE_CONSOLE_CLIENT_ID。
替代方案:使用API密钥(仅测试场景)
如果不想用OAuth认证,可生成API密钥,通过Alamofire发送请求:
private func updateWithAPIKey() { let apiKey = "YOUR_API_KEY" let url = "https://sheets.googleapis.com/v4/spreadsheets/\(spreadsheetId)/values/\(range)?valueInputOption=RAW&key=\(apiKey)" let params = ["values": [["TestName", 50, ISO8601DateFormatter().string(from: Date())]]] AF.request(url, method: .put, parameters: params, encoding: JSONEncoding.default) .responseJSON { response in debugPrint(response) } }
注意:API密钥存在泄露风险,仅适用于测试,正式应用优先使用OAuth认证。
内容的提问来源于stack exchange,提问作者Markku Jyrinki
相关产品推荐
相关产品推荐

