如何排查Slack Bolt触发Modal时出现的404错误
问题:Slack Modal弹窗唤起失败(404错误)
问题背景
正在开发Slack应用的Modal弹窗功能,点击消息内的按钮唤起弹窗,使用block builder构建JSON结构。发送普通消息功能正常,但唤起弹窗时出现404错误,弹窗无法正常打开。
现有代码
Bolt应用处理代码
app.action('watch-skill-video', async ({ ack, action, client, say, respond }) => { ack() const msg = await watchLayoutBuilder('some value', 'someother value') console.log('Message - ' + msg) await respond(JSON.parse(msg)) });
生成的Modal JSON结构
{ "title": { "type": "plain_text", "text": "Abc" }, "submit": { "type": "plain_text", "text": "Submit" }, "blocks": [ { "text": { "type": "plain_text", "text": "Dummy" }, "type": "button" } ], "type": "modal" }
错误信息
[ERROR] bolt-app UnknownError: Request failed with status code 404 at asCodedError (/Users/rajeshghosh/Projects/pwa-slack/node_modules/@slack/bolt/dist/errors.js:35:12) at App.handleError (/Users/rajeshghosh/Projects/pwa-slack/node_modules/@slack/bolt/dist/App.js:608:57) at App.processEvent (/Users/rajeshghosh/Projects/pwa-slack/node_modules/@slack/bolt/dist/App.js:593:25) at processTicksAndRejections (internal/process/task_queues.js:95:5) at async SocketModeClient.<anonymous> (/Users/rajeshghosh/Projects/pwa-slack/node_modules/@slack/bolt/dist/receivers/SocketModeReceiver.js:126:17) { code: 'slack_bolt_unknown_error', original: Error: Request failed with status code 404 at createError (/.../node_modules/@slack/bolt/node_modules/axios/lib/core/createError.js:16:15) at settle (/.../node_modules/@slack/bolt/node_modules/axios/lib/core/settle.js:17:12) at IncomingMessage.handleStreamEnd (/.../node_modules/@slack/bolt/node_modules/axios/lib/adapters/http.js:322:11) at IncomingMessage.emit (events.js:412:35) at IncomingMessage.emit (domain.js:475:12) at endReadableNT (internal/streams/readable.js:1334:12) at processTicksAndRejections (internal/process/task_queues.js:82:21) { config: { transitional: [Object], adapter: [Function: httpAdapter], transformRequest: [Array], transformResponse: [Array], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, validateStatus: [Function: validateStatus], headers: [Object], proxy: false, method: 'post', url: 'https://hooks.slack.com/actions/TFTS42ALT/3855892288214/7lmakyKKBAvk0paJguVzxoih', data: '{"title":{"type":"plain_text","text":"Abc"},"submit":{"type":"plain_text","text":"Submit"},"blocks":[{"text":{"type":"plain_text","text":"Dummy"},"type":"button"}],"type":"modal"}' }, request: ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: true, chunkedEncoding: false, shouldKeepAlive: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, _contentLength: null, _hasBody: true, _trailer: '', finished: true, _headerSent: true, socket: [TLSSocket], _header: 'POST /actions/TFTS42ALT/3855892288214/7lmakyKKBAvk0paJguVzxoih HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'Content-Type: application/json\r\n' + 'User-Agent: axios/0.26.1\r\n' + 'Content-Length: 179\r\n' + 'Host: hooks.slack.com\r\n' + 'Connection: close\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: noopPendingOutput], agent: [Agent], socketPath: undefined, method: 'POST', maxHeaderSize: undefined, insecureHTTPParser: undefined, path: '/actions/TFTS42ALT/3855892288214/7lmakyKKBAvk0paJguVzxoih', _ended: true, res: [IncomingMessage], aborted: false, timeoutCb: null, upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'hooks.slack.com', protocol: 'https:', _redirectable: [Writable], [Symbol(kCapture)]: false, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype] }, response: { status: 404, statusText: 'Not Found', headers: [Object], config: [Object], request: [ClientRequest], data: [Object] }, isAxiosError: true, toJSON: [Function: toJSON] } } [ERROR] An unhandled error occurred while Bolt processed (type: block_actions, error: Error: Request failed with status code 404)
问题分析与解决方案
核心问题
使用respond()方法发送Modal是错误的,respond()仅用于回复触发动作的消息(如修改原消息或发送新消息到频道),它的请求目标是Slack Webhook URL;而Modal需要通过Slack API的views.open方法唤起,不能通过Webhook实现。
修正代码
将respond()替换为client.views.open(),并传入正确的参数结构:
app.action('watch-skill-video', async ({ ack, action, client }) => { await ack(); const modal = await watchLayoutBuilder('some value', 'someother value'); const modalJson = JSON.parse(modal); await client.views.open({ trigger_id: action.trigger_id, // 必须从触发动作的action对象中获取,有效期3秒 view: modalJson }); });
关键说明
trigger_id是唤起Modal的必填参数,必须从触发按钮的action对象中获取,且仅在触发后的3秒内有效。client.views.open()是Bolt官方提供的唤起Modal的标准API方法,会正确调用Slack的API端点,而非Webhook。- 确保Slack应用已配置所需权限:包括
commands、users:read基础权限,以及views:open权限。
内容的提问来源于stack exchange,提问作者Rajesh
相关产品推荐
相关产品推荐

