Express路由跨Discord服务器访问时报assignments is not a function问题排查
问题根源
你的报错assignments is not a function是变量名冲突导致的函数覆盖,核心原因有两点:
- 循环迭代变量未声明,直接覆盖了顶层导出函数
你在fetchCalls.js里三个业务函数内部的遍历逻辑,都没有给迭代变量加let/const声明:
// 错误写法 for( assignments of apiData) for( announcements of apiData) for( discussions of apiData)
未声明的变量会自动提升为模块级全局变量,第一次执行循环时就会把你原本导出的同名函数直接覆盖为接口返回的数组元素,第二次再调用该函数时,变量已经不是函数类型,自然触发报错。重启服务后变量重置恢复为函数,所以报错会暂时消失。
2. 模块级全局变量共享导致并发请求参数混乱
你在fetchCalls.js顶层声明的obj、course、url、access_token、guildid、channelid都是模块全局变量,多个并发请求进来时,后到的请求会覆盖前序请求的参数,导致数据返回错乱。
修复方案
1. 修复循环变量覆盖问题
给所有for循环的迭代变量加上const声明,同时避免和外层函数重名:
// assignments遍历改成 for(const assignment of apiData) { // 内部用到迭代变量的地方统一改为assignment const string = ["```Name: ${assignment.name}", `Description:\n ${assignment.description}`,`Due Date: ${assignment.due_at}\n````]; } // announcements遍历改成 for(const announcement of apiData) {} // discussions遍历改成 for(const discussion of apiData) {}
2. 消除模块全局变量污染
把所有需要用到的参数改为函数内部传递,不要用顶层全局变量存储:
- 删掉
fetchCalls.js顶层的var obj; var course; var url; var access_token; var guildid; var channelid;声明 - 修改
getFetchData函数为直接返回需要的参数,不要给全局变量赋值:
function getFetchData(document) { return { obj: 'course_' + document._courseid, course: document._courseid, url: 'https://' + document.prefix + '.instructure.com/api/v1/', access_token: document.access_token } }
- 每个异步处理函数内部接收返回的参数使用,以
assignmentsFunc为例:
const fetchParams = await getRecord({guild_id : `${guildid}`}, getFetchData); // 后续的url、course、access_token都从fetchParams中读取 const res1 = await fetch(fetchParams.url + `/courses/${fetchParams.course}/assignments?order_by=due_at`, { headers: { Authorization: `Bearer ${fetchParams.access_token}` } })
3. 其他附带问题修复
- Express路由没有返回响应会导致请求一直超时,给每个路由加上响应逻辑:
app.all('/assignments', async (request, response) => { await assignments(request.body.guild, request.body.channel); response.sendStatus(200); });
- MongoDB的
updateChannelID方法中docs.updateOne(query,insert)没有加await,会导致异步逻辑错乱,在前面补充await即可。
内容的提问来源于stack exchange,提问作者Zboyz
相关产品推荐
相关产品推荐

