30天学习计划走到第9天,我终于在 SAP BTP 上用 SAP Build Code 把第一个 Node.js 应用跑了起来。如果你也正在折腾这条路,大概率会和我有同感——写代码本身并不难,难的是把本地的 Node.js 环境、云上的 BTP 账号、Build Code 开发空间、Cloud Foundry 部署这一整条链路理清楚。这篇日记不打算只写“怎么点按钮”,我会把每一步背后的选型逻辑、为什么要这样配置、以及我实际踩过的坑都摊开来讲,希望能帮你少走几天的弯路。
1. 第9天:为什么我决定在 SAP Build Code 里写“第一个” Node.js 应用
1.1 前8天我到底在学什么
先交代一下背景。这个30天学习计划的前8天,我一直在啃概念:SAP BTP 是什么、Cloud Foundry 运行环境、子账户和试用账户的区别、服务目录里那些眼花缭乱的服务、角色集合和权限分配……听起来都是“认识一下”的内容,但等到真正动手才发现,这些概念不先搞清楚,后面每一步都会卡住。
比如,如果你不知道“子账户”和“空间”是两个层级,你在部署应用时就不知道该看哪个界面的日志;如果你不懂“服务实例”和“服务凭证”,你在连接数据库时就会一脸懵。所以第9天不是我“终于”决定写代码,而是前面的地基打得差不多了,可以开始把知识串起来了。我选择从 Node.js 而不是 Java 起步,原因很简单:Node.js 的项目启动快、依赖轻、一个人用试用账号跑起来几乎不占什么资源,非常适合做第一个跑通全流程的应用。
1.2 SAP Build Code 到底解决了什么问题
很多人第一次看到 SAP Build Code 会把它当成一个“低代码拖拽平台”,这个理解其实不对。它更准确的定位是:SAP 官方的云上全栈开发环境,是 SAP Business Application Studio(BAS)的增强版本。
为什么我需要它?因为我手上这台电脑的操作系统比较乱,本地装了一堆不同版本的 Node、Python、Java,再装 SAP 的开发插件很容易互相打架。而 SAP Build Code 把整个开发环境搬到了云端:我只需要在浏览器里打开一个 Dev Space,里面已经预装了 Node.js、npm、pnpm、SAP Fiori tools、Cloud Foundry CLI 等一堆工具,还能直接用 SAP Cloud Application Programming Model(CAP)和 Joule 这种生成式 AI 辅助能力。
换句话说,它解决的最核心痛点是:你不用再花一整天配置本地开发环境,也能获得一个和 SAP BTP 无缝衔接的开发工作区。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备:Node.js 版本、本地工具链与 BTP 账号
2.1 Node.js 版本选择:不是越新越好
先说结论:用 LTS 版本,不要追最新版。Node.js 的版本节奏很快,很多 SAP 相关工具链的兼容性测试都基于 LTS 版本,你用了一个刚发布还没被工具链“喂熟”的版本,很容易出现奇怪的问题。
我在准备环境时搜索相关排查资料时,发现不少人都遇到过这类报错:
bash复制error installing 24.20.0: node.js v24.20.0 is not yet released or is not available
这个报错的意思很直白:你想安装的 Node.js 版本号在软件源里根本不存在,或者还没有正式发布。常见原因是你用的 Node 版本管理工具(比如 nvm)版本太老,它内置的版本列表没有更新;或者镜像源同步不及时。解决办法也很简单:更新 nvm 本身,重新拉取版本列表,然后指定一个确定存在的 LTS 版本。
另一类高频报错是 pnpm 引发的:
bash复制error: this version of pnpm requires at least node.js v22.13
这是版本“不够新”的问题。新版 pnpm 对 Node.js 有最低版本要求,而你的系统默认 Node 太老。不要硬去装旧版 pnpm,直接用 nvm 切换到一个满足要求的 Node LTS 版本,或者把 pnpm 升级到与当前 Node 匹配的版本。
我整理了一张版本选择表,方便你对照:
| 使用场景 | 推荐版本 | 说明 |
|---|---|---|
| 本地日常开发 | Node.js 20 LTS 或 22 LTS | 兼容性最好,社区资料多 |
| SAP Fiori 工具链 | 20+ | 新版脚手架对 Node 18 的支持已逐步弱化 |
| 新版 pnpm | 22.13+ | 不满足会直接拒绝安装依赖 |
| 不建议 | 非 LTS 最新版 | 比如 v24,容易出现“not yet released”类问题 |
如果你还没装 Node.js,我的建议是不要从官网下载一个“最新版”装完就完事。优先装 nvm(Windows 上用 nvm-windows,macOS 上用 nvm),这样后面想换版本就是一条命令的事。
2.2 端口占用检查和包管理器的选择
开发 Node.js 应用经常会遇到“端口被占用”。SAP CAP 项目默认端口是 4004,Fiori 前端开发服务器默认端口是 5000 系,如果你本机之前跑过别的服务,很容易撞上。
检查端口占用,Windows 上可以用:
bash复制netstat -ano | findstr :4004
macOS 或 Linux 上可以用:
bash复制lsof -i :4004
看到结果后有两条路:要么把占用端口的进程停掉,要么在项目配置里改端口。我建议改端口,因为系统里有些后台进程你强行杀掉可能会引发别的问题。在 SAP CAP 项目里,可以通过 cds.env.port 或者启动命令参数来改:
bash复制npm start -- --port 4005
包管理器方面,SAP Build Code 的 Dev Space 里预装了 npm 和 pnpm,两个都能用。我的建议是:如果你主要跟着 SAP 官方教程走,用 npm 就够了;如果你依赖比较多、想要更快的安装速度和更严格的依赖锁定,用 pnpm。但注意不要在同一个项目里混用两个包管理器,那个 package-lock.json 和 pnpm-lock.yaml 互相覆盖的问题,我见过不止一次。
顺带提一句,如果你用的某个桌面工具一直卡在“installing node.js dependencies”这一步,大概率不是网络问题,而是它调用的 Node 版本和工具要求不匹配。优先检查环境变量里 PATH 指向的 Node 到底是哪个版本,再做下一步。
2.3 开通 SAP BTP 试用账号并订阅 Build Code
这部分稍微有点绕,我尽量说得直白。
首先,SAP BTP 有一个免费的 Trial 账户,注册后平台会给你一个子账户和基本的 Cloud Foundry 环境配额。注册流程不复杂,进入到 SAP BTP Cockpit 后跟着引导走就行,选区域时建议选离你近的区域,比如 ap-ap 或 us-east。需要注意,试用账户有时效限制和资源限制,但跑一个 Node.js 应用绰绰有余。
其次,要在 BTP 上使用 SAP Build Code,你需要打开 Service Marketplace,找到 SAP Build Code 这个服务,然后创建订阅。这一步经常有人卡住,因为默认的试用子账户里没有这个服务。解决办法是回到 Subaccount 页面,确认你所在的区域支持 SAP Build Code(大部分主流区域都支持),然后手动在 Service Marketplace 里搜索并订阅。
订阅完成后,还有一个权限问题:你的用户角色里需要有 SAP Build Code 相关的角色集合,否则打开时会提示没有权限。常见做法是在 BTP Cockpit 的 Security -> Users 里,给当前用户分配 Build Code 相关的开发角色。
我当时的教训是:开通订阅后立刻试用,结果页面一直在转圈,退出重新登录才正常。如果你也遇到这种情况,先别急着清缓存,检查一下用户角色是不是真的分配到位了。
3. 创建项目:从 Dev Space 到第一个 Node.js 服务
3.1 创建 Dev Space 时该选哪个模板
SAP Build Code 的工作单元叫 Dev Space,你可以把它理解成一台预装好各种开发工具的云上虚拟机,但不用自己维护。打开 Dev Space Manager,新建空间时会让你选模板,常见的有:
- Full-Stack Cloud Application
- Basic
- SAP Fiori
- SAP HANA Native Application
本文场景我推荐选 Full-Stack Cloud Application。这个模板预装了 CAP 开发工具、Fiori 工具、CDS 编译器和 Cloud Foundry 相关插件,基本覆盖了开发到部署的全流程。如果你只想练 Node.js 基础语法,选 Basic 也够,但后面要接 CAP 或部署时还得补装插件,不如一次到位。
创建空间后需要等一小会,状态变成 RUNNING 才能点击进入。我当时等了大概三分钟,如果超过五分钟还卡在 STARTING,可以试试停止空间重建一个。
3.2 用 CAP 模板还是裸 Node.js 模板
进入 Dev Space 后,你会看到一个类似 VS Code 的界面。这里有两种方式创建 Node.js 应用:
第一种,直接用终端初始化一个 Express 应用。如果你就是想验证 Node.js 能不能跑,这是最快的方式。
bash复制mkdir myapp
cd myapp
npm init -y
npm install express
然后写一个 server.js:
javascript复制const express = require('express');
const app = express();
const port = process.env.PORT || 4004;
app.get('/', (req, res) => {
res.send('Hello from SAP BTP Build Code!');
});
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
第二种,使用 SAP CAP 项目模板。CAP 是 SAP 官方主推的云应用编程模型,它的好处是:你定义一个数据模型,框架自动帮你生成 CRUD 接口、 OData/REST 服务、数据库表结构等等,你不用手写一堆样板代码。
在终端里执行:
bash复制cds init bookshop
cd bookshop
npm install
npm start
cds init 会生成一个标准的 CAP 项目骨架,目录结构大致如下:
text复制bookshop/
├── app/ # 前端 UI 项目(Fiori 应用)
├── db/ # 数据模型定义(.cds 文件)
│ └── schema.cds
├── srv/ # 服务定义和实现
│ ├── service.cds
│ └── service.js
├── package.json
└── manifest.yml # 云部署配置
我的建议是:如果你追求“最短路径跑通”,先试第一种;但如果你想在 SAP BTP 上做正经的应用开发,直接学第二种,因为 CAP 才是你后续真正会长期使用的东西。
3.3 定义数据模型并启动服务
以 CAP 项目为例,打开 db/schema.cds,定义一个简单的实体:
cds复制namespace my.bookshop;
entity Books {
key ID : UUID @(core.Computed) : true;
title : String;
author : String;
stock : Integer;
}
然后在 srv/service.cds 里暴露一个服务:
cds复制using my.bookshop from '../db/schema';
service CatalogService {
entity Books as projection on my.bookshop.Books;
}
保存后,在终端执行:
bash复制cds watch
cds watch 会监听文件变化并自动重启服务,开发体验非常好。启动成功后,终端会显示类似这样的地址:
text复制[cds] - server listening on { url: 'http://localhost:4004' }
在浏览器里访问 http://localhost:4004/catalog/Books,你就能看到 CAP 自动生成的 REST 接口返回的数据。因为数据库里还没有数据,返回的可能是一个空数组,但这已经足以验证整个链路是通的。
4. 在 Dev Space 中调试和验证:如何确认应用真的在跑
4.1 从浏览器访问 Dev Space 里的服务
Dev Space 里的 localhost 并不是你本地电脑的 localhost,它是云端环境里的回环地址。SAP Build Code 提供了端口转发机制,你只需要在 BAS 的终端里启动服务,然后在菜单栏找到 Preview 或者 Ports 面板,添加端口号,系统会生成一个可访问的公网预览链接。
如果你不想用界面,也可以在终端里用 curl 来验证:
bash复制curl http://localhost:4004/catalog/Books
能看到 JSON 响应就说明服务是活的。这一步千万别跳过,因为本地服务跑起来之后,你还需要确认它能在云端被访问到,提前暴露问题总比部署后再排查强。
4.2 日志怎么看
CAP 项目启动时会输出很多日志,学会看日志是排查问题的基础。Node.js 应用里你可以用 console.log 输出关键信息,在 CAP 的服务实现文件里写下:
javascript复制const cds = require('@sap/cds');
module.exports = cds.service.impl(async function () {
this.on('READ', 'Books', async (req) => {
console.log('Someone is reading Books');
});
});
当你调用接口时,终端里会打印对应日志。如果应用启动时就直接崩溃,错误信息通常也会打印在启动日志中。常见的问题比如 .cds 文件语法错误,日志里会明确告诉你出错的文件和行号,照着改就行。
4.3 遇到 500 错误先别慌
我在第一次启动时,访问接口报了一个 500 错误,当时第一反应是查代码,结果折腾半天发现是数据库连接的问题——CAP 默认尝试连接 SQLite,但 Dev Space 模板里没有初始化好数据库文件。
遇到这种情况,如果是 SQLite,可以先删掉 db.sqlite 这类缓存文件再重启;如果是更复杂的数据库服务,检查环境变量和 package.json 里的依赖是否配置正确。总之,遵循一条原则:先看启动日志,再动代码。
5. 部署到 SAP BTP Cloud Foundry:让应用脱离本地运行
5.1 准备 manifest.yml 和 CF CLI
开发环境里跑通只是第一步,最终目标是把应用部署到 SAP BTP 的 Cloud Foundry 运行时上。Cloud Foundry 是一个 PaaS 平台,它负责管理应用运行所需的基础设施和运行时,你只需要告诉它应用怎么启动、需要多少内存就够了。
部署前需要在项目根目录创建一个 manifest.yml:
yaml复制applications:
- name: my-bookshop
memory: 512M
instances: 1
random-route: true
path: .
buildpack: nodejs_buildpack
这里的几个参数说明一下:
name:应用名,在 Cloud Foundry 中全局唯一memory:内存配额,Node.js 应用建议 512M,256M 容易出现 OOMrandom-route: true:自动生成一个随机路由,避免路由冲突buildpack: nodejs_buildpack:告诉平台用 Node.js 构建包来运行这个应用
Dev Space 里已经预装了 CF CLI,确认一下版本:
bash复制cf --version
然后登录到你的 Cloud Foundry 环境。API 地址在 BTP Cockpit 的 Cloud Foundry 环境信息里能看到,格式类似:
bash复制cf login -a https://api.cf.us10.hana.ondemand.com
登录时,一般会要求提供邮箱和密码,如果账号绑定了 SAP Universal ID,用那个登录也行。
5.2 cf push 完整过程与常见失败
执行部署命令:
bash复制cf push
Cloud Foundry 会自动读取 manifest.yml,上传代码,下载依赖,然后启动应用。整个过程第一次会比较慢,因为要安装依赖并下载 buildpack,后面会快一些。
如果你用的是 CAP 项目,别忘了 cf push 前先执行一次 npm ci 之类的构建步骤,确保 node_modules 状态统一。我踩过的一个坑是:本地 npm install 生成的 lock 文件版本和云端 buildpack 解析出来的版本不一致,导致云端启动时依赖缺失。解决办法是固定 package-lock.json,并尽量用同一套包管理器。
启动超时也是高频问题。如果依赖安装太慢,超过默认超时时间,可以显式加大超时:
bash复制cf push -t 180
5.3 部署后端口问题的关键点
本地开发时,我们习惯硬编码端口 4004,但 Cloud Foundry 会自动注入一个环境变量 PORT,应用必须监听这个端口才能被平台识别为健康。
所以代码里一定要这样写:
javascript复制const port = process.env.PORT || 4004;
很多新手部署后看到日志一直报“No space left on device”或者“Instance not healthy”,其实就是因为应用还在监听 4004,而不是 $PORT。这个问题排查起来很隐蔽,因为本地一切正常,只有部署后才出问题。
部署成功后,CF CLI 会输出应用的 URL,类似 https://my-bookshop.cfapps.us10.hana.ondemand.com,浏览器直接访问这个地址,再拼上 /catalog/Books,就能看到和本地一样的结果。
5.4 查看云端日志
部署后如果遇到问题,别猜,看日志:
bash复制cf logs my-bookshop --recent
日志里会包含 buildpack 启动阶段的信息、应用自身的 console 输出、以及崩溃时的堆栈信息。结合我在前面讲的版本问题、端口问题,绝大多数情况都能在日志里找到答案。
6. 第9天的踩坑清单与几条真心建议
6.1 我实际遇到并解决的问题汇总
把这几天的混乱整理成一张表,方便你对照排查:
| 症状 | 可能原因 | 解决办法 |
|---|---|---|
| Dev Space 一直处于 STARTING | 空间创建异常或资源不足 | 停止并重建 Dev Space |
| 打开 Build Code 提示无权限 | 用户角色未分配 | 在 BTP Cockpit 中分配 Build Code 相关角色集合 |
| 本地 npm install 报 node-gyp 错误 | Node 版本与依赖编译环境不匹配 | 切换到与工具链匹配的 LTS Node 版本 |
cds watch 后端口被占用 |
本地已有进程占用 4004 | 用 netstat 或 lsof 排查并换端口 |
| 接口返回 500 | CAP 数据库初始化失败 | 删除本地 SQLite 缓存文件或检查连接配置 |
| cf push 后应用一直崩溃 | 应用未监听 $PORT 端口 |
检查代码中 process.env.PORT 的逻辑 |
| 部署超时 | 依赖安装过慢 | cf push -t 180 调大超时时间 |
| 部署后接口 404 | 路由路径不对 | 确认 manifest.yml 中 random-route 生成的实际 URL |
6.2 给同样在自学 SAP BTP 的人几点建议
第一,不要跳着看官方文档。SAP 的文档体系非常庞大,但核心路径是清晰的:BTP Cockpit -> 子账户 -> 空间 -> 服务 -> 应用。每一步都建立在前一步概念之上,跳过去的坑后面都会补回来。
第二,版本一致性非常重要。本地的 Node.js 版本、npm 版本、CAP 版本、云端 buildpack 版本,能保持一致就保持一致。我自己的教训是,本地用 Node 18 开发的 CAP 项目,部署到云端默认 Node 20 的 buildpack 上,某些依赖的编译结果不一样,导致启动失败。后来我在项目里显式声明了引擎版本:
json复制"engines": {
"node": ">=20.0.0"
}
第三,遇到问题先看日志,再查代码。人的直觉很不可靠,尤其在环境类问题上。先去 Dev Space 终端看启动日志,再去 CF CLI 里看部署日志,日志能给到的信息远比“多读几遍代码”多。
6.3 下一步的学习安排
第9天跑通这个流程后,我打算第10天把 MySQL 或 SAP HANA Cloud 数据库接进来,让数据真正落到数据库里,而不仅仅是 SQLite 临时文件。再往后会尝试用 SAP Fiori tools 生成一个简单的前端界面,把后端服务和界面串起来,那就是一个完整的最小应用了。
写这篇日记时,我又重新建了一个全新的 Dev Space 把步骤走了一遍,发现最耗时间的其实不是写代码,而是等 Dev Space 启动、等依赖安装、等应用部署。所以强烈建议你养成一个习惯:每次改动只改一个变量,保存前想清楚这次操作会不会影响版本和端口,能省下大量等待和排查的时间。下一步,我会继续往数据库和前端的方向推进,等有新的踩坑经验再来更新日志。
