Node.js配置public路由出现TypeError: chosenHandler is not a function报错
Node.js 原生项目TypeError: chosenHandler is not a function解决及静态资源访问实现
核心报错现象
- 报错触发位置为
chosenHandler(data,function(statusCode,payload,contentType)行,抛出TypeError: chosenHandler is not a function - 新增
chosenHandler = trimmedPath.indexOf('public/') > -1 ? handlers.public : chosenHandler;代码时报错出现,删除该行后程序恢复正常,但无法访问public目录下的静态资源 - 项目仅使用Node.js原生能力开发,无第三方依赖
报错根因
当路径匹配命中public目录规则时,handlers.public为非函数类型,常见两种场景:
handlers.js模块未显式导出public方法,导致引入后该属性为undefined- 原路径匹配逻辑存在漏洞,非预期场景下错误赋值
handlers.public
分步解决方案
1. 校验handlers.public的导出正确性
打开handlers.js,确认public方法已被显式导出,符合CommonJS规范,示例正确导出格式:
// handlers.js 内的public方法定义 var public = function(data, callback) { // 静态资源处理逻辑 }; // 模块导出列表,*必须包含public* module.exports = { index: index, ping: ping, users: users, tokens: tokens, checks: checks, favicon: favicon, public: public // 遗漏该导出会导致引入后public为undefined };
2. 修正public路径匹配逻辑
原代码trimmedPath.indexOf('public/') > -1存在边界问题:既无法匹配根路径public,也可能误匹配api/public/xxx这类非预期路径。替换为Node.js原生支持的前缀匹配:
原错误行:
chosenHandler = trimmedPath.indexOf('public/') > -1 ? handlers.public : chosenHandler;
替换为:
// 匹配所有以public开头的路径,覆盖public目录下所有资源 chosenHandler = trimmedPath.startsWith('public') ? handlers.public : chosenHandler;
说明:
startsWith()为Node.js v4.0+原生支持的字符串方法,无需引入任何第三方库。
3. 增加handler合法性校验(可选)
为避免后续同类报错,可在调用chosenHandler前增加校验,兜底使用404 handler:
// 新增于chosenHandler赋值完成后、调用前 if (typeof chosenHandler !== 'function') { debug('路径%s的handler非函数,降级为404处理', trimmedPath); chosenHandler = handlers.notFound; }
纯Node.js实现public静态资源访问参考逻辑
若handlers.public尚未实现,可使用原生fs、path模块完成静态资源读取,示例代码:
// handlers.js 内的public handler实现 var path = require('path'); var fs = require('fs'); var public = function(data, callback) { // 剥离路径中的public前缀,获取实际资源相对路径 const relativeAssetPath = data.trimmedPath.replace(/^public\/?/, ''); // 拼接资源绝对路径,默认访问public根路径下的index.html const fullAssetPath = relativeAssetPath === '' ? path.join(__dirname, '/../public/index.html') : path.join(__dirname, '/../public/', relativeAssetPath); // 读取静态资源文件 fs.readFile(fullAssetPath, 'utf8', (err, content) => { if (err) { // 资源不存在返回404 callback(404, '', 'plain'); return; } // 根据文件后缀匹配Content-Type,与server层的类型判断逻辑对齐 const ext = path.extname(fullAssetPath).slice(1).toLowerCase(); let contentType = 'plain'; if (ext === 'html') contentType = 'html'; if (ext === 'css') contentType = 'css'; if (ext === 'png') contentType = 'png'; if (ext === 'jpg') contentType = 'jpg'; if (ext === 'ico') contentType = 'favicon'; callback(200, content, contentType); }); };
内容的提问来源于stack exchange,提问作者Hemant
相关产品推荐
相关产品推荐

