在GCF(NodeJS)中通过Sendgrid事件Webhook同步邮件状态至BigQuery遇BQ错误
解决SendGrid事件Webhook数据写入BigQuery时的「必须提供至少1行插入」错误
问题根源
你的代码默认SendGrid Webhook发送的是数组格式的事件数据,但SendGrid在触发单条事件(比如单封邮件的送达/退回)时,会直接发送单个JSON对象而非数组。这就导致代码里的for (var i = 0; i < data.length; i++)循环根本不会执行,最终rows数组为空,BigQuery自然抛出「必须提供至少1行插入」的错误。
另外还有两个潜在问题:
- 错误处理里
err.response.insertErrors[1]可能出现数组越界,当只有一个错误时会报错 - 没有添加日志排查接收到的原始数据,不利于定位问题
修复方案
1. 兼容单条/多条事件格式
先判断接收的req.body是否为数组,若不是则包装成数组,确保循环能正常执行。
2. 完善日志与错误处理
添加日志打印原始请求数据,方便排查;同时修正错误处理逻辑,避免越界。
修改后的完整代码
const { BigQuery } = require("@google-cloud/bigquery"); const projectId = "Project_id"; const dataset = "Dataset_name"; const tableName = "Table_name"; const bigQuery = new BigQuery({ projectId }); exports.helloWorld = (req, res) => { // 打印原始请求数据,用于排查 console.log("Received request body:", req.body); const timestamp = new Date().getTime().toString(); let data = req.body; // 兼容单条事件(对象)和多条事件(数组)的格式 if (!Array.isArray(data)) { data = [data]; } const rows = data.map(item => ({ hit_timestamp: timestamp, email: item.email, event: item.event, category: Array.isArray(item.category) ? item.category.join(",") : String(item.category), event_id: item.sg_event_id, event_payload: JSON.stringify(item) })); // 只有当有数据时才调用插入方法 if (rows.length > 0) { send_to_bq(rows); } else { console.warn("No valid rows to insert into BigQuery"); } res.status(200).send("Event processed"); }; function send_to_bq(rows) { bigQuery .dataset(dataset) .table(tableName) .insert(rows) .then(() => { console.log(`Successfully inserted ${rows.length} rows into BigQuery`); }) .catch((err) => { console.error("BigQuery insertion error:", err); // 安全处理错误信息,避免越界 if (err.response?.insertErrors) { err.response.insertErrors.forEach((error, index) => { console.error(`Insert error at row ${index}:`, error.error); }); } }); }
额外说明
- SendGrid Webhook的事件格式:单条事件是对象,批量事件是数组,所以必须做格式兼容
category字段可能是数组(SendGrid允许设置多个分类),代码里处理成逗号分隔的字符串,避免BigQuery字段类型不匹配- 添加了空数组判断,避免无效的BigQuery插入请求
内容的提问来源于stack exchange,提问作者Prasenjit
相关产品推荐
相关产品推荐

