如何用原生JSON调用Firebase云函数?iOS调用checkUsers遇422错误
问题分析
你遇到的问题根源在于Firebase HTTPS Callable函数和普通HTTP POST请求的参数传递格式完全不同。你的云函数是按照普通Express POST请求的逻辑读取req.body.emails,但iOS端用了httpsCallable方法调用——这种方式会把参数包裹在特定的data结构里,导致云函数找不到req.body.emails,从而触发422错误提示。
下面给你两种针对性的解决方案,你可以根据自己的需求选择:
方案1:修改iOS代码,使用普通HTTP POST请求
既然你的云函数已经适配了Postman的普通POST请求,那iOS端可以直接发送标准POST请求,不用Callable函数:
func checkEmails( _ contacts: [SIContact], _ completion: @escaping (([SIContact]) -> Void) ) { // 替换成你的云函数实际URL guard let url = URL(string: "https://your-cloud-function-domain.cloudfunctions.net/checkUsers") else { print("Invalid cloud function URL") return completion(contacts) } let data = ["aaa", "akshit.zaveri@gmail.com", "bbb"] let params = ["emails": data] do { let jsonData = try JSONSerialization.data(withJSONObject: params) var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = jsonData URLSession.shared.dataTask(with: request) { (data, response, error) in if let error = error { print("Error while checking emails \(error)") return completion(contacts) } guard let responseData = data else { print("No response data received") return completion(contacts) } do { guard let results = try JSONSerialization.jsonObject(with: responseData) as? [[String: Any]] else { print("Invalid response format from cloud function") return completion(contacts) } print(results) // 这里可以根据results更新contacts后再调用completion completion(contacts) } catch { print("Failed to parse response: \(error)") completion(contacts) } }.resume() } catch { print("Failed to serialize request params: \(error)") completion(contacts) } }
方案2:修改云函数,适配HTTPS Callable格式
如果你想继续用iOS的httpsCallable方法,需要调整云函数的参数读取逻辑——Callable函数的参数会放在req.body.data里,而非直接在req.body,同时建议用异步写法简化代码:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.checkUsers = functions.https.onCall(async (data, context) => { // 从Callable函数的data对象中获取emails if (data.emails === undefined) { throw new functions.https.HttpsError('invalid-argument', 'Missing email addresses input'); } const emailsToCheck = data.emails; if (emailsToCheck.length === 0) { throw new functions.https.HttpsError('invalid-argument', 'No email addresses provided'); } const existingEmails = []; // 异步遍历所有用户(避免回调嵌套) let pageToken; do { const userPage = await admin.auth().listUsers(1000, pageToken); userPage.users.forEach(user => { existingEmails.push(user.email.toLowerCase()); }); pageToken = userPage.pageToken; } while (pageToken); // 检查每个邮箱是否存在 const emailsChecked = emailsToCheck.map(email => ({ email: email, exists: existingEmails.includes(email.toLowerCase()) })); return emailsChecked; });
注意:改用Callable函数后,Postman的调用方式也要调整——POST请求的Body需要是
{"data": {"emails": ["aaa", "akshit.zaveri@gmail.com", "bbb"]}},同时请求头要包含Content-Type: application/json。
内容的提问来源于stack exchange,提问作者Akshit Zaveri
相关产品推荐
相关产品推荐

