Firebase Cloud Function模拟器正常 部署报JSON解析错误
我编写了一个Cloud Function,用于删除帖子及其关联的comments子集合。该函数在模拟器中可正常执行帖子删除操作,但部署到Firebase时出现以下错误:
i functions: updating Node.js 16 function recursiveDelete(us-central1)...
Function failed on loading user code. This is likely due to a bug in the user code. Error message:
Error: please examine your function logs to see the error cause
Additional troubleshooting documentation can be found at official logging guide page
Functions deploy had errors with the following functions:
recursiveDelete(us-central1)
按照提示查看Google Cloud函数日志,发现报错:
SyntaxError: Unexpected token p in JSON at position 1
at .JSON.parse
at .parse (
/layers/google.nodejs.functions-framework/functions-framework/node_modules/body-parser/lib/types/json.js:89
)
相关代码
Cloud Function 代码
const functions = require("firebase-functions"); const firebase_tools = require('firebase-tools'); const admin = require('firebase-admin'); admin.initializeApp(); /** * Initiate a recursive delete of documents at a given path. * @param {string} data.path the document or collection path to delete. */ exports.recursiveDelete = functions .runWith({ timeoutSeconds: 540, memory: '2GB' }) .https.onCall(async (data, context) => { const path = data[0].path; console.log(`Running cloud function recursiveDelete on ${path}`); await firebase_tools.firestore .delete(path, { project: process.env.GCP_PROJECT, recursive: true, yes: true, token: '...', force: true }); return { path: path }; });
Flutter客户端调用代码
static Future<void> delete(String ref) async { if (FirebaseAuth.instance.currentUser == null) { throw Exception('Must be logged in'); } await FirebaseFunctions.instance .httpsCallable('recursiveDelete') .call([{'path': 'posts/$ref'}]) .then((value) => logger("Post deleted: ${value.data}")) .catchError((error) => logger.error("Failed to delete post: $error")); }
该功能在模拟器中运行正常,日志输出如下:
I/flutter (26907): [Post] [INFO] Post deleted: {path: posts/Gk4TeWEgZmm0QUcaqTrk}
完整部署堆栈跟踪
=== Deploying to 'sightings-dev'... i deploying functions i functions: ensuring required API cloudfunctions.googleapis.com is enabled... i functions: ensuring required API cloudbuild.googleapis.com is enabled... ✔ functions: required API cloudfunctions.googleapis.com is enabled ✔ functions: required API cloudbuild.googleapis.com is enabled ✔ artifactregistry: required API artifactregistry.googleapis.com is enabled i functions: preparing codebase default for deployment i functions: preparing functions directory for uploading... i functions: packaged /Users/strijdhaftig/sightings/frontend/flutter/sightings/functions (55.13 KB) for uploading ✔ functions: functions folder uploaded successfully i functions: updating Node.js 16 function recursiveDelete(us-central1)... Function failed on loading user code. This is likely due to a bug in the user code. Error message: Error: please examine your function logs to see the error cause. Additional troubleshooting documentation can be found at official logging guide page. Please visit official troubleshooting page for in-depth troubleshooting documentation. Functions deploy had errors with the following functions: recursiveDelete(us-central1) i functions: cleaning up build files... Error: There was an error deploying functions Having trouble? Try again or contact support with contents of firebase-debug.log
报错核心来自两个代码问题:
- 硬编码无效token:代码里写死
token: '...',线上部署时Functions框架加载代码阶段会尝试解析该字段,无效的占位字符串直接触发JSON解析错误,也就是日志里Unexpected token p in JSON at position 1的来源。本地模拟器对该参数校验宽松,会自动读取本地登录凭证忽略无效传值,所以本地可以正常运行。 - Callable函数传参格式不规范:客户端用数组包裹参数
[{'path': 'posts/$ref'}]、服务端用data[0].path取值不符合Callable函数的传参设计,线上环境序列化校验更严格,容易触发解析异常。
按以下两点修改即可:
- 删除硬编码的
token字段,firebase-tools在Cloud Function运行环境中会自动拉取当前服务的身份凭证,不需要手动传入token。 - 调整传参格式,去掉数组包裹,直接传递对象参数。
修改后的Cloud Function代码
const functions = require("firebase-functions"); const firebase_tools = require('firebase-tools'); const admin = require('firebase-admin'); admin.initializeApp(); /** * Initiate a recursive delete of documents at a given path. * @param {string} data.path the document or collection path to delete. */ exports.recursiveDelete = functions .runWith({ timeoutSeconds: 540, memory: '2GB' }) .https.onCall(async (data, context) => { // 直接读取对象属性,不需要数组下标 const path = data.path; console.log(`Running cloud function recursiveDelete on ${path}`); await firebase_tools.firestore .delete(path, { project: process.env.GCP_PROJECT, recursive: true, yes: true, force: true }); return { path: path }; });
修改后的Flutter调用代码
static Future<void> delete(String ref) async { if (FirebaseAuth.instance.currentUser == null) { throw Exception('Must be logged in'); } await FirebaseFunctions.instance .httpsCallable('recursiveDelete') // 直接传入对象,不使用数组包裹 .call({'path': 'posts/$ref'}) .then((value) => logger("Post deleted: ${value.data}")) .catchError((error) => logger.error("Failed to delete post: $error")); }
修改完成后重新部署函数即可正常运行。
内容的提问来源于stack exchange,提问作者Dan1ell

