使用Slack Block Kit发布Lighthouse报告时遇400错误求助
Slack Webhook结合Block Kit发送Lighthouse报告报400 "no_text"错误排查
尝试通过Slack Webhook结合Block Kit将Lighthouse性能报告发布到Slack时,始终收到400状态码,响应信息为"no_text",需排查问题并实现完整报告的格式化发送。
Lighthouse报告JSON格式
{ "Performance Score": [ { "Performance": " 59 %", "Color": "ORANGE" }, { "Accessibility": " 85 %", "Color": "ORANGE" }, { "BestPractices": " 96 %", "Color": "GREEN" }, { "SEO": " 100 %", "Color": "GREEN" } ], "Performance KPI": [ { "First Contentful Paint (FCP)": "1.7 s", "Speed Index": "4.7 s", "Largest Contentful Paint (LCP)": "8.7 s", "Total Blocking Time (TBT)": "70 ms", "Cumulative Layout Shift (CLS)": "0.012" } ] }
最初构造的Block Kit结构
const reportblocks = [ { "type": "section", "text": { "type": "mrkdwn", "text": "*Performance Score*" }, "fields": [ { "type": "mrkdwn", "text": `• Performance: ${payload['Performance Score'][0]['Performance']} (${payload['Performance Score'][0]['Color']})` }, { "type": "mrkdwn", "text": `• Accessibility: ${payload['Performance Score'][1]['Accessibility']} (${payload['Performance Score'][1]['Color']})` }, { "type": "mrkdwn", "text": `• Best Practices: ${payload['Performance Score'][2]['BestPractices']} (${payload['Performance Score'][2]['Color']})` }, { "type": "mrkdwn", "text": `• SEO: ${payload['Performance Score'][3]['SEO']} (${payload['Performance Score'][3]['Color']})` } ] }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Performance KPI*" }, "fields": [ { "type": "mrkdwn", "text": `• First Contentful Paint (FCP): ${payload['Performace KPI'][0]['First Contentful Paint (FCP)']}` }, { "type": "mrkdwn", "text": `• Speed Index: ${payload['Performace KPI'][0]['Speed Index']}` }, { "type": "mrkdwn", "text": `• Largest Contentful Paint (LCP): ${payload['Performace KPI'][0]['Largest Contentful Paint (LCP)']}` }, { "type": "mrkdwn", "text": `• Total Blocking Time (TBT): ${payload['Performace KPI'][0]['Total Blocking Time (TBT)']}` }, { "type": "mrkdwn", "text": `• Cumulative Layout Shift (CLS): ${payload['Performace KPI'][0]['Cumulative Layout Shift (CLS)']}` } ] } ];
收到的错误响应
Slack notification sent successfully. Response: {"status":"fail","statusCode":400,"headers":{"date":"Mon, 08 Apr 2024 16:46:09 GMT","server":"Apache","vary":"Accept-Encoding","strict-transport-security":"max-age=31536000; includeSubDomains; preload","referrer-policy":"no-referrer","x-slack-unique-id":"ZhQfUQd89LozgBIYrwHtqgAAACM","x-slack-backend":"r","access-control-allow-origin":"*","x-frame-options":"SAMEORIGIN","content-type":"text/html","content-length":"7","via":"1.1 slack-prod.tinyspeck.com, envoy-www-iad-lopevkmr, envoy-edge-canary-bom-bccpskqz","x-envoy-attempt-count":"1","x-envoy-upstream-service-time":"217","x-backend":"main_normal main_canary_with_overflow main_control_with_overflow","x-server":"slack-www-hhvm-main-iad-szna","x-slack-shared-secret-outcome":"no-match","x-edge-backend":"envoy-www","x-slack-edge-shared-secret-outcome":"no-match"},"response":"no_text"}
修改后的单一Section结构
const reportblocks = { type: "section", text: { type: "mrkdwn", text: ` *Performance Score:* • Performance: ${payload["Performance Score"][0]["Performance"]} (${payload["Performance Score"][0]["Color"]}) • Accessibility: ${payload["Performance Score"][1]["Accessibility"]} (${payload["Performance Score"][1]["Color"]}) • Best Practices: ${payload["Performance Score"][2]["BestPractices"]} (${payload["Performance Score"][2]["Color"]}) • SEO: ${payload["Performance Score"][3]["SEO"]} (${payload["Performance Score"][3]["Color"]}) *Performance KPI:* • First Contentful Paint (FCP): ${payload["Performace KPI"][0]["First Contentful Paint (FCP)"]} • Speed Index: ${payload["Performace KPI"][0]["Speed Index"]} • Largest Contentful Paint (LCP): ${payload["Performace KPI"][0]["Largest Contentful Paint (LCP)"]} • Total Blocking Time (TBT): ${payload["Performace KPI"][0]["Total Blocking Time (TBT)"]} • Cumulative Layout Shift (CLS): ${payload["Performace KPI"][0]["Cumulative Layout Shift (CLS)"]} `, }, };
可正常运行的简化代码
const Slack = require("slack-node"); const logger = require("../../reporting/logger"); const apiEndPoints = require("../../config/apiEndPoints"); const webhookurl = `${apiEndPoints.SLACK_SDET_URL}`; async function sendSlackNotification(payload) { try { logger.info(`Sending Slack notification to: ${webhookurl}`); const slack = new Slack(); slack.setWebhook(webhookurl); const reportblocks = [ { type: 'section', text: { type: 'mrkdwn', text: '*Performance Score:*' }, fields: payload['Performance Score'].map(score => ({ type: 'mrkdwn', text: `${Object.keys(score)[0]}: ${Object.values(score)[0]}`, })), } ]; const message = { blocks: reportblocks , }; slack.webhook(message, function (err, response) { if (err) { logger.error(`Error occurred while sending Slack notification: ${err}`); } else { logger.info(`Slack notification sent successfully: ${JSON.stringify(response)}`); } }); } catch (error) { logger.error("Error occurred:", error); } } sendSlackNotification(); module.exports = { sendSlackNotification, };
问题排查与解决方案
核心问题分析
- 必填字段缺失:Slack Webhook要求消息必须包含
text字段作为降级内容(即使使用blocks),仅传blocks会触发"no_text"错误。 - 拼写错误:原代码中
payload['Performace KPI']存在拼写错误(少一个'r',应为Performance KPI),导致模板字符串渲染出undefined,使内容无效。 - 内容渲染异常:拼写错误引发的无效内容会让Slack判定消息无有效文本,进而返回400错误。
修复后的完整代码
const Slack = require("slack-node"); const logger = require("../../reporting/logger"); const apiEndPoints = require("../../config/apiEndPoints"); const webhookurl = `${apiEndPoints.SLACK_SDET_URL}`; async function sendSlackNotification(payload) { try { logger.info(`Sending Slack notification to: ${webhookurl}`); const slack = new Slack(); slack.setWebhook(webhookurl); // 修复拼写错误:Performace → Performance const performanceKPIs = payload['Performance KPI'][0]; const reportblocks = [ { "type": "section", "text": { "type": "mrkdwn", "text": "*📊 Lighthouse Performance Report*" } }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Performance Score*" }, "fields": [ { "type": "mrkdwn", "text": `• Performance: ${payload['Performance Score'][0]['Performance']} (${payload['Performance Score'][0]['Color']})` }, { "type": "mrkdwn", "text": `• Accessibility: ${payload['Performance Score'][1]['Accessibility']} (${payload['Performance Score'][1]['Color']})` }, { "type": "mrkdwn", "text": `• Best Practices: ${payload['Performance Score'][2]['BestPractices']} (${payload['Performance Score'][2]['Color']})` }, { "type": "mrkdwn", "text": `• SEO: ${payload['Performance Score'][3]['SEO']} (${payload['Performance Score'][3]['Color']})` } ] }, { "type": "divider" }, { "type": "section", "text": { "type": "mrkdwn", "text": "*Performance KPI*" }, "fields": [ { "type": "mrkdwn", "text": `• FCP: ${performanceKPIs['First Contentful Paint (FCP)']}` }, { "type": "mrkdwn", "text": `• Speed Index: ${performanceKPIs['Speed Index']}` }, { "type": "mrkdwn", "text": `• LCP: ${performanceKPIs['Largest Contentful Paint (LCP)']}` }, { "type": "mrkdwn", "text": `• TBT: ${performanceKPIs['Total Blocking Time (TBT)']}` }, { "type": "mrkdwn", "text": `• CLS: ${performanceKPIs['Cumulative Layout Shift (CLS)']}` } ] } ]; const message = { // 添加必填的text降级内容 text: "Lighthouse性能报告已生成,详情请查看下方内容", blocks: reportblocks }; slack.webhook(message, function (err, response) { if (err) { logger.error(`Error occurred while sending Slack notification: ${err}`); } else { logger.info(`Slack notification sent successfully: ${JSON.stringify(response)}`); } }); } catch (error) { logger.error("Error occurred:", error); } } // 调用时需传入正确的Lighthouse报告payload // sendSlackNotification(yourLighthousePayload); module.exports = { sendSlackNotification, };
关键修复点
- 添加
text字段:在消息对象中加入降级文本,满足Slack Webhook的必填要求。 - 修正拼写错误:将
Performace KPI改为Performance KPI,确保数据能正确读取。 - 优化Block结构:添加标题和分隔线提升可读性,简化KPI字段的显示文本。
- 变量提取:将KPI对象单独提取,减少重复代码,提升可维护性。
内容的提问来源于stack exchange,提问作者Jyoti Prakash Mallick
相关产品推荐
相关产品推荐

