#firebase #google-cloud-firestore #google-cloud-functions
#firebase #google-cloud-firestore #google-cloud-функции
Вопрос:
Я довольно новичок в функциях Firebase / Firestore / Cloud и пробовал небольшой проект, в котором клиентское приложение вызывает облачную функцию Firebase для генерации некоторых случайных ключей (случайных чисел), добавляет их в Firestore и при успешной записи возвращает эти ключи в клиентское приложение. Вроде как генератор случайных чисел.
Функция правильно вызывается клиентом (в соответствии с Firebase Console), генерирует ключи, проверяет, существуют ли они в Firestore, и, если нет, добавляет их. Все работает до той части, где он должен возвращать результат клиенту. Здесь клиент никогда не получает результат (массив ключей). Фактически, обратный вызов в клиентском приложении (iOS / Swift) никогда не вызывается.
Я подозреваю, что проблема заключается в возврате обещания? Согласно документации Firebase здесь, асинхронные вызываемые объекты должны возвращать обещание, хотя я не совсем уверен, что то, что я делаю, правильно https://firebase.google.com/docs/functions/callable
Вот код облачной функции:
export const generateRandomKeys = functions.https.onCall(async (data, context) => {
// Read data passed from client
const numberOfKeys = data.numberOfKeys
console.log("Number of keys to generate: ", numberOfKeys)
// Generate some keys
const generatedKeys = KeyMaker.newKeys(numberOfKeys)
try {
const randomkeys = []
// Write keys to DB
for (const key of generatedKeys) {
const addedKey = await writeKeyToDB(key)
randomkeys.push(addedKey)
}
return Promise.resolve(JSON.stringify(randomkeys))
} catch (error) {
console.log("Error has occured: ", error)
throw new Error("An Error has occured: " error)
}
})
async function writeKeyToDB(key: string){
try {
// Check if a document with the same key already exists in the DB
const docRef = db.collection("randomKeys").doc(key)
const doc = await docRef.get()
// Document with same key found!
if (doc.exists) {
// Generate a new key and try again
const newKey = KeyMaker.newKey()
console.log("Will generate a new key and try again!. New key: ", newKey)
await writeKeyToDB(newKey)
}
const keyDoc = {
somefield: somevalue,
}
// Write to DB then return result
await docRef.set(keyDoc)
return Promise.resolve(key)
} catch (error) {
return Promise.reject(error)
}
}
Клиент (Swift)
public static func generateNewRandomNumbers(numberOfKeys: Int) {
FirebaseApp.configure()
let functions = Functions.functions(region: FIRESTORE_REGION)
functions.httpsCallable("generateRandomKeys").call(["numberOfKeys": numberOfKeys]) { (result, error) in
// Nothing here executes
print("----------got reply---------")
if let error = error as NSError? {
if error.domain == FunctionsErrorDomain {
let code = FunctionsErrorCode(rawValue: error.code)
let message = error.localizedDescription
print("Error (String(describing: code)): " message)
}
}
if let keys = (result?.data as? [String]) {
dump(keys)
}
}
}
Комментарии:
1. Если вы используете async / await, вам не нужно явно возвращать обещание. Возвращаемое значение будет автоматически завернуто в обещание. Но я не знаю, проблема ли это здесь.
2. Спасибо за быстрый ответ. Я удалил обещания и вернул напрямую значения, но, похоже, это ничего не изменило. Я добавил в OP код клиента, мне кажется, что там нет проблемы
3. @DougStevenson Теперь я наконец получил результат в клиентском приложении, я могу распечатать его, используя
dump(results?.data)
какие результаты,Optional(["838483","33411","94949"])
но я не могу определить тип результатов. данные для его чтения. Я пытался[String]
, но, похоже, это не так. Какой тип это будет?
Ответ №1:
Не объединяйте Async/Await
и Promise
. Async
функционирует как сам возврат Promise
.
Сначала измените возврат вашей облачной функции на :
return JSON.stringify(randomkeys);
Также в writeKeyToDb
изменении возврат к:
return key;
и catch
часть для:
throw Error(error);
Я также вижу проблему в том, что в облачной функции вы вызываете свою writeKeyToDb
функцию с 2 параметрами, но у этой функции есть только один. Но этот код, вероятно, выполняется
Комментарии:
1. Внес изменения, но не помогло. Что касается идентификатора пользователя, в моем исходном коде было еще несколько переменных, и я немного изменил его, чтобы упростить код для публикации здесь. Итак, я забыл пару вещей здесь и там. Но исходный код работает точно так же. Я также опубликовал код клиента. Есть идеи, почему функция async может не возвращаться?
2. Ну, вы пытались обменять этот возврат облачной функции на что-то статическое
return ['onekey','secondKey']
?3. Вы совершенно правы. Я попытался просто вернуть только значение, и оно действительно не вернулось, поэтому я еще раз взглянул на код клиента и по ошибке внес изменения в неправильный класс swift. Итак, теперь я получаю ответный вызов, но теперь я не знаю, как проанализировать result.data. Когда я это делаю
dump(result?.data)
, я вижу ключи в консоли XCode, ноif let licenseKeys = (result?.data as? [String])
не выполняется. Разве результат не является массивом строк?4. @UMAD создайте для этого новый билет. Потому что это не ошибка облачной функции
Ответ №2:
Наконец-то нашел проблему, спасибо Дугу и Доминику за то, что они направили меня в правильном направлении. Я удалил обещания и вернул непосредственно значения, но, что более важно, мне не нужно было преобразовывать массив в JSON. Я наткнулся на документацию HTTPSCallableResult
Я просто изменил это
return JSON.stringify(randomkeys);
Для
return randomkeys
и на клиенте, вместо
if let keys = (result?.data as? [String]) {
dump(keys)
}
Я делаю
if let keys = (result?.data as? NSArray) {
dump(keys)
}