問題情形
本地NodeJS應用使用Egg腳手架構建,本地運行測試完全沒有問題,發布后App Service后不能運行。通過登錄到kudu后(https://<your web site>.scm.chinacloudsites.cn)后,在日志中發現找不到一個文件或路徑的錯誤。通過在kudu的CMD窗口執行npm start命令,發現錯誤是一致,懷疑是對Egg中某個框架的不支持。
詳細日志
Application has thrown an uncaught exception and is terminated:
SystemError [ERR_SYSTEM_ERROR]: A system error occurred: uv_os_get_passwd returned ENOENT (no such file or directory)
at Object.userInfo (os.js:272:11)
at module.exports (D:\home\site\wwwroot\pynode\node_modules\node-homedir\index.js:10:26)
at AppWorkerLoader.getHomedir (D:\home\site\wwwroot\pynode\node_modules\egg-core\lib\loader\egg_loader.js:163:36)
at AppWorkerLoader.getAppInfo (D:\home\site\wwwroot\pynode\node_modules\egg-core\lib\loader\egg_loader.js:174:23)
at new EggLoader (D:\home\site\wwwroot\pynode\node_modules\egg-core\lib\loader\egg_loader.js:87:25)
at new AppWorkerLoader (D:\home\site\wwwroot\pynode\node_modules\egg\lib\loader\app_worker_loader.js:9:1)
at new EggCore (D:\home\site\wwwroot\pynode\node_modules\egg-core\lib\egg.js:118:19)
at new EggApplication (D:\home\site\wwwroot\pynode\node_modules\egg\lib\egg.js:43:5)
at new Application (D:\home\site\wwwroot\pynode\node_modules\egg\lib\application.js:60:5)
at Object.<anonymous> (D:\home\site\wwwroot\pynode\index.js:3:13)
在詳細的log文件中,可以看見全面的錯誤信息。並指出了報錯的源文件為:(D:\home\site\wwwroot\pynode\node_modules\node-homedir\index.js:10:26),在源代碼中,找出了問題的根源。
問題原因
node_modules\node-homedir\index.js 源碼:
1 'use strict'; 2 3 const os = require('os'); 4 5 module.exports = () => { 6 if (process.env.MOCK_HOME_DIR) return process.env.MOCK_HOME_DIR; 7 8 if (typeof os.userInfo === 'function') { 9 try { 10 const homedir =os.userInfo().homedir; 11 if (homedir) return homedir; 12 } catch (err) { 13 if (err.code !== 'ENOENT') throw err; 14 } 15 } 16 17 if (typeof os.homedir === 'function') { 18 return os.homedir(); 19 } 20 21 return process.env.HOME; 22 };
在第十行代碼中,使用了os對象,而在App Service中,由於是sandbox 模式下,所以某些操作被禁止了。關於禁止的說明可以參考:https://github.com/projectkudu/kudu/wiki/Azure-Web-App-sandbox#general-sandbox-restrictions
解決方案
在查看源代碼后,想解決它就有兩種辦法:
1) 在修改node-homedir\index.js中的源代碼,把里面 os.userInfo().homedir 的部分替換成在App Service中的Homedir路徑,hardcode這一部分。如 const homedir =”D:\home\site\wwwroot\“;//os.userInfo().homedir;
2) 最快速且無代碼改動方案。在App Service的應用程序設置中(Applicaiton Settings)添加一個名MOCK_HOME_DIR的設置,並設置其值為D:\home\site\wwwroot\ (為應用程序發布的默認路徑)。 這樣node-homedir的源代碼就不會進入到os部分。直接在第一行就返回需要的homedir.
PS: 這里是把NodeJS的應用發布在Windows的環境中遇見的問題,如發布在App Service For Linux則可以避免類似問題。