Axios调用带HTTP触发器的Google Cloud Functions时出现超时问题
Google Cloud Functions HTTP触发器写入Google Sheets时,Axios请求超时问题排查与解决
问题场景
我正在用带HTTP触发器的Google Cloud Functions把数据写入Google Sheets,云函数代码如下:
exports.writeDataMaterialCollection = functions.https.onRequest( (req, res) => { if (req.method === "POST") { console.log(req.body); res.set("Access-Control-Allow-Origin", "*"); const sheets = google.sheets({ version: "v4" }); var jwt = getJwt(); var apiKey = getApiKey(); var spreadsheetId = "sheetIDxxxxxxxxx"; var range = "A:L"; var row = ["data"]; sheets.spreadsheets.values.append( { spreadsheetId: spreadsheetId, range: range, auth: jwt, key: apiKey, valueInputOption: "RAW", resource: { values: [row] } }, (err, result) => { if (err) { throw err; } else { console.log(result.data.updates.updatedRange); res.status(200).send(result.data.updates.updatedRange); } } ); } } );
用curl发起POST请求时数据能正常写入:
curl -d '{"test": "wert"}' -X POST http://localhost:5001/XXXX/writeDataMaterialCollection
但在Vue.js里用Axios发起请求时,云函数返回throw new Error("Function timed out."),Axios代码:
axios( "http://localhost:5001/XXXXX/writeDataMaterialCollection", { method: "POST", headers: { "content-type": "application/json", "Access-Control-Allow-Origin": "*" }, data: { daten1: 23 } } ).then(response => (self.writeDataResult = response));
问题根源分析
- 未处理OPTIONS预检请求:浏览器发起跨域POST请求时,会先发送OPTIONS预检请求,你的云函数只处理了POST方法,其他方法(比如OPTIONS)没有返回任何响应,导致函数一直挂起直到超时。
- 客户端错误设置CORS头:
Access-Control-Allow-Origin是服务器返回给客户端的响应头,不需要在Axios的请求头里设置,这属于多余操作,反而可能干扰请求处理。 - 错误处理逻辑不当:当
sheets.spreadsheets.values.append回调出现错误时,直接throw err在云函数HTTP触发器中不会正确返回错误响应,会导致函数进程异常,无法结束请求。
解决方案
1. 修正云函数的CORS与请求方法处理
确保处理所有HTTP方法,尤其是OPTIONS,并且在所有分支都返回响应:
exports.writeDataMaterialCollection = functions.https.onRequest(async (req, res) => { // 先设置CORS头,所有请求都需要 res.set("Access-Control-Allow-Origin", "*"); res.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); res.set("Access-Control-Allow-Headers", "Content-Type"); // 处理OPTIONS预检请求,直接返回204 if (req.method === "OPTIONS") { res.status(204).send(""); return; } if (req.method === "POST") { console.log(req.body); const sheets = google.sheets({ version: "v4" }); const jwt = getJwt(); const apiKey = getApiKey(); const spreadsheetId = "sheetIDxxxxxxxxx"; const range = "A:L"; // 可以根据req.body来构造row,比如用传入的daten1 const row = [req.body.daten1 || "default-data"]; try { // 改用async/await方式,更易维护和错误处理 const result = await sheets.spreadsheets.values.append({ spreadsheetId: spreadsheetId, range: range, auth: jwt, key: apiKey, valueInputOption: "RAW", resource: { values: [row] } }); console.log(result.data.updates.updatedRange); res.status(200).send(result.data.updates.updatedRange); } catch (err) { console.error("写入表格出错:", err); // 返回错误响应,而不是throw res.status(500).send(`写入失败: ${err.message}`); } } else { // 处理其他方法,比如GET,返回不允许的提示 res.status(405).send("仅支持POST和OPTIONS请求"); } });
2. 修正Axios请求代码
移除不必要的Access-Control-Allow-Origin请求头,并加上错误捕获方便调试:
axios("http://localhost:5001/XXXXX/writeDataMaterialCollection", { method: "POST", headers: { "content-type": "application/json" }, data: { daten1: 23 } }).then(response => { self.writeDataResult = response; }).catch(err => { console.error("请求出错:", err); });
额外注意事项
- 本地测试时,确保Google Cloud Functions emulator正常运行,端口和路径与请求一致。
- 确认
getJwt()和getApiKey()返回的凭据有效,具备操作目标Google Sheets的权限。 - 部署到线上时,建议不要将
Access-Control-Allow-Origin设为*,而是指定你的前端域名,提升安全性。
内容的提问来源于stack exchange,提问作者Vinz
相关产品推荐
相关产品推荐

