如何将参数从 Dart 传递到用 Typescript 编写的 Cloud 函数,它还给了我错误代码 UNAUTHENTICATED
Posted
技术标签:
【中文标题】如何将参数从 Dart 传递到用 Typescript 编写的 Cloud 函数,它还给了我错误代码 UNAUTHENTICATED【英文标题】:How to pass arguments from Dart to Cloud functions written in Typescript and it also gives me error code UNAUTHENTICATED 【发布时间】:2020-08-07 14:24:02 【问题描述】:Dart 函数(将token
传递给sendToDevice
):
Future<void> _sendNotification() async
CloudFunctions functions = CloudFunctions.instance;
HttpsCallable callable = functions.getHttpsCallable(functionName: "sendToDevice");
callable.call(
'token': await FirebaseMessaging().getToken(),
);
index.ts
我定义了sendToDevice
方法的文件。
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
const fcm = admin.messaging();
export const sendToDevice = functions.firestore
.document('users/uid')
.onCreate(async snapshot =>
const payload: admin.messaging.MessagingPayload =
notification:
title: 'Dummy title',
body: `Dummy body`,
click_action: 'FLUTTER_NOTIFICATION_CLICK'
;
return fcm.sendToDevice(tokens, payload); // how to get tokens here passed from above function?
);
问题:
如何接收从我的 Dart 函数 _sendNotification
传递到 Typescript 的 sendToDevice
函数的令牌。
当我直接在 index.ts
文件中传递令牌时,我遇到了这个异常:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] 未处理的异常:PlatformException(functionsError, Cloud function failed with exception., code: UNAUTHENTICATED, details: null, message: UNAUTHENTICATED)
谁能解释一下我是否应该在这里验证某些东西?命令 firebase login
显示我已经登录。我对 Typescript 很陌生,所以请耐心等待这些愚蠢的问题。
【问题讨论】:
您是否尝试在创建新文档时触发此功能?如果是这样,您为什么再次从客户端调用相同的函数? @StewieGriffin 是的,实际上这就是我要找的东西,因为我不知道打字稿,不知道这段代码在做什么。 那么您应该将您的设备令牌存储在您的数据库中,以便在触发函数时查询它们,而不是将它们从客户端传递给函数。流程应该是这样的:创建文档 -> 触发云函数 -> 函数从 db 查询令牌 -> 它推送通知 【参考方案1】:这里有几件事要提:
1st 'getHttpsCallable' 中使用的函数必须由 https 触发器触发(参考here)。这里我们有一个由firestore document create触发的函数,所以它不起作用。
2nd 你的函数没有参数,但是你用参数调用它。如果您需要使用参数调用云函数的示例,您可以在pud.dev找到它
3rd 目前我没有机会玩它,但我认为如果你用token
参数实现https触发功能,你应该可以传递这个参数。
希望对你有帮助!
更新:
根据doc https 触发函数必须用functions.https
创建。文档中有一个很好的例子。要以这种方式触发功能,您可以在传递所需数据时添加请求正文。
【讨论】:
感谢您的建议,但很抱歉它们不是很有用。例如,您说getHttpsCallable
应该由https
触发,您能告诉我我应该在代码中的哪个位置进行更改吗?
第二,您提供的示例没有显示他们如何处理index.js
文件中传递的参数,他们只提供了Dart代码,我的代码类似于它,你能告诉我我该怎么做在index.js
里面这样做?
对不起@iKeepChangingName 我以为很清楚,我添加了对Google文档的引用,希望对您有所帮助!【参考方案2】:
您的 Flutter 代码似乎是正确的,但 Cloud Function 有问题。
sendToDevice
函数不是可调用函数。它是一个Cloud Firestore Triggers,它只意味着在创建与users/uid
匹配的文档时自动调用。
相反,您需要创建一个Callable Function,见下文
export const sendToDevice = functions.https
.onCall(async (data) =>
const token = data; // Data is what you'd send from callable.call
const payload: admin.messaging.MessagingPayload =
notification:
title: 'Dummy title',
body: `Dummy body`,
click_action: 'FLUTTER_NOTIFICATION_CLICK'
;
return fcm.sendToDevice(token, payload);
);
【讨论】:
感谢您的回答,我正在使用您的代码,但我收到此错误Unhandled Exception: PlatformException(functionsError, Cloud function failed with exception., code: UNAUTHENTICATED, details: null, message: UNAUTHENTICATED)
,我仔细检查了我的token
不是null
。
在这种情况下,我建议执行一些调试步骤,以确保首先,仔细检查您的凭据是否在同一个 Firebase 项目中。其次,删除 FCM 部分只是为了测试调用的函数。访问您的 Firebase 控制台并尝试使用您获得的令牌发送通知。您可能还想查看 Cloud Function Dashboard 上的日志记录【参考方案3】:
您已经创建了一个数据库触发器,您应该创建一个如下所示的可调用函数
exports.sendToDevice = functions.https.onCall(async (data, context) =>
const payload: admin.messaging.MessagingPayload =
notification:
title: 'Dummy title',
body: `Dummy body`,
click_action: 'FLUTTER_NOTIFICATION_CLICK'
;
return await fcm.sendToDevice(data.token, payload);
);
【讨论】:
【参考方案4】:此答案可能无法解决您的问题,但可以让您尝试一些事情,并且您将在此过程中学习。不幸的是,我无法让可调用的 https 与模拟器一起工作。我可能会很快提交一个关于它的 github 问题。根据我尝试的本地 URL,flutter 应用程序不断收到不同类型的无法识别的错误。
很高兴您已经解决了其中一个问题:您使用的是文档触发器 (onCreate
) 而不是 https 可调用对象。但是现在,您正在运行一个 https 可调用对象,并且 Flutter 应用程序需要直接与您的函数进行通信。以后,你可以在本地运行函数模拟器,并做很多console.log
'ing 来了解它是否真的被触发了。
我有几个问题/你可以尝试:
您的用户是否已登录 Flutter 应用程序?FirebaseAuth.instance.currentUser()
会告诉你。
ios 和 android 都会出现这个问题吗?
将一些日志添加到您的 typescript 函数中,然后重新部署。通过 StackDriver 或终端 firebase functions:log --only sendToDevice
阅读最新日志。 (sendToDevice 是你的可调用函数名)
您是否正在部署到云端并使用最新的功能部署进行测试?您实际上可以使用local emulator 进行测试。在 Android 上,URL 是10.0.2.2:5001
,如上所示。您还需要在终端中运行adb reverse tcp:5001 tcp:5001
。如果你在云端,那么firebase login
没关系,我认为你的函数应该已经有了凭据。
调用模拟器https callable:
HttpsCallable callable = CloudFunctions.instance
.useFunctionsEmulator(origin: "http://10.0.2.2:5001")
.getHttpsCallable(functionName: "sendToDevice");
而iOS你需要遵循here的解决方案。
我发现了一个错误。您至少应该在等待 promise 解决的地方执行return await fcm.sendToDevice()
,否则云函数运行时将在您的函数解决之前终止它。或者,为了调试,您可以将它保存到一个变量中,而不是在您的云函数中返回 sendToDevice
,然后 console.log
'd 它。你会看到它实际上是一个尚未真正解决的承诺(或 dart 术语中的未来)。
const messagingDevicesResponse: admin.messaging.MessagingDevicesResponse = await fcm.sendToDevice(
token,
payload
);
console.log( messagingDevicesResponse );
return;
【讨论】:
【参考方案5】:公开函数
问题与凭据有关。如果问题得到解决,您可以更改 CF 和 sheck 的安全策略。了解如何管理 CF 上的权限here
【讨论】:
以上是关于如何将参数从 Dart 传递到用 Typescript 编写的 Cloud 函数,它还给了我错误代码 UNAUTHENTICATED的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 Dart 中的 onTap 函数将值传递到另一个屏幕?
如何将任意数据从 Dart 聚合物 Web 组件传递给单击事件处理函数
Flutter/Dart 如何将索引从 Listview.builder 传递到项目小部件