最近在Windows环境下启动Cesium项目时,执行yarn start命令后遇到了一个令人困惑的错误:
bash复制file:///E:/code/html_code/20260227_cesium_code/server.js:408
server.address().port,
^
TypeError: Cannot read properties of null (reading 'port')
Node.js v24.11.0
error Command failed with exit code 1.
这个错误表面看起来是JavaScript中常见的空值引用错误,但实际原因却隐藏得更深。作为一名长期使用Cesium进行三维地理可视化开发的老手,我见过各种稀奇古怪的问题,但端口冲突导致的这类错误确实容易让人走弯路。
关键提示:当你在开发环境中看到
Cannot read properties of null (reading 'port')这类错误时,第一反应不应该是去检查代码中的空值处理,而应该先确认服务器端口是否被占用。这是我多年开发总结出的经验法则。
错误信息指向server.address().port这行代码,表面上看是因为server.address()返回了null,导致无法读取port属性。但为什么server.address()会返回null呢?
通过分析Node.js的底层行为,我们发现:当app.listen()方法无法成功绑定到指定端口时(通常是因为端口已被占用),server.address()就会返回null。这才是问题的真正根源。
在计算机网络中,端口是应用程序与网络通信的端点。每个端口在同一时间只能被一个进程独占使用。Cesium的本地开发服务器默认使用8080端口,而许多其他应用程序(如GeoServer、Jenkins等)也偏爱使用这个端口。
当两个程序尝试绑定到同一个端口时,后启动的程序会收到EADDRINUSE错误(地址已在使用中)。在Node.js中,这个错误会被转换为server.address()返回null,进而导致我们看到的Cannot read properties of null错误。
在Windows系统下,我们可以使用以下PowerShell命令检查8080端口是否被占用:
powershell复制netstat -ano | findstr :8080
如果输出类似以下内容,则说明端口确实被占用:
code复制TCP 0.0.0.0:8080 0.0.0.0:0 LISTENING 5916
这里的5916是占用端口的进程ID(PID)。
知道PID后,我们可以进一步确认是哪个程序占用了端口:
powershell复制tasklist | findstr 5916
输出示例:
code复制GeoServer.exe 5916
这表明是GeoServer占用了8080端口。如果是Windows服务,还可以使用更详细的查询命令:
powershell复制Get-CimInstance Win32_Service | Where-Object { $_.ProcessId -eq 5916 } | Select Name,DisplayName,State
这是最简单直接的解决方案,特别适合临时开发场景:
bash复制yarn start --port 8081
然后通过http://localhost:8081访问应用。
优点:
注意事项:
如果确定不需要运行占用端口的程序(如GeoServer),可以将其停止。
services.msc并回车powershell复制sc.exe stop GeoServer
适用场景:
如果需要长期同时运行Cesium和GeoServer,可以修改GeoServer的端口:
etc/jetty.xml或etc/jetty-http.xml文件<Set name="port">8080</Set>为其他端口(如8082)实施建议:
当调用app.listen(port)时,Node.js底层会尝试以下操作:
如果端口已被占用,第二步会失败,抛出EADDRINUSE错误。此时server.address()将返回null,因为服务器实际上并未成功启动。
更健壮的代码应该这样处理端口监听:
javascript复制const server = app.listen(port, () => {
console.log(`Server running on port ${server.address().port}`);
});
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
console.error(`Port ${port} is already in use`);
// 可以在这里实现自动端口递增等逻辑
}
});
这种实现方式能更清晰地报告问题本质,而不是抛出晦涩的null.port错误。
为了避免频繁的端口冲突,建议为开发环境中的各种服务制定明确的端口分配方案:
| 服务类型 | 推荐端口范围 |
|---|---|
| 前端开发服务器 | 3000-3999 |
| API后端服务 | 4000-4999 |
| 数据库/中间件 | 5000-5999 |
| 地理空间服务 | 6000-6999 |
可以在package.json中配置智能端口选择脚本:
json复制{
"scripts": {
"start": "node scripts/start.js",
"start:auto": "node scripts/start-with-port-check.js"
}
}
其中start-with-port-check.js可以实现端口自动检测和递增功能。
全面了解系统端口使用情况:
powershell复制netstat -ano -p TCP | findstr LISTENING
Windows资源监视器提供了更直观的端口查看方式:
有时端口被占用是因为父进程启动了子进程:
powershell复制Get-Process -IncludeUserName | Format-Table Id,Name,UserName,ParentId
虽然本文以Windows为例,但在其他操作系统上原理相同,只是命令有所差异:
bash复制lsof -i :8080
bash复制kill -9 <PID>
bash复制systemctl stop geoserver
当处理端口冲突问题时,还需要注意:
如果按照上述方法仍无法解决问题,可以考虑:
通过这次问题排查,我们不仅解决了Cannot read properties of null (reading 'port')错误,还深入理解了Node.js服务启动机制和端口管理原理。记住几个关键点:
netstat和tasklist诊断端口占用情况在实际开发中,我通常会为每个项目创建一个start-dev.sh脚本,自动处理端口检测和分配,这可以显著减少此类问题的发生频率。