☰
LoopBack 4 SOAP 计算器应用:运行、测试与端口配置实战指南
2026/10/15 17:37:41 网站建设 项目流程
  • 后端
  • 微服务

【免费下载链接】loopback-next

LoopBack makes it easy to build modern API applications that require complex integrations.

项目地址:https://gitcode.com/gh_mirrors/lo/loopback-next
点击查看免费下载

导读

本文是 LoopBack 4(loopback-next)官方 soap-calculator 教程的收尾章节,聚焦"运行与测试"这一实战环节:你将学会通过npm start启动基于 SOAP 连接器的 REST 应用,用curl或浏览器验证/add/50/50等端点,理解响应中 JSON 结果与 XML 信封(envelope)并存的含义,并掌握通过application.ts构造参数修改监听 IP 与端口的方法。读完本文,你既能跑通完整的 SOAP→REST 集成链路,也能在真实部署中自如调整服务监听配置。

本文对应的教程文档位于 soap-calculator-tutorial-run-and-test.md,仓库中还提供了可直接运行参照的完整示例工程 examples/soap-calculator。教程完整步骤依次为:SOAP Web 服务概览 → 应用脚手架 → 添加数据源 → 添加服务代理 → 添加控制器 → 运行与测试,本文即最后一步。


运行应用:npm start与启动日志解读

完成控制器编写后,在应用根目录(即soap-calculator目录)执行:

npm start

正常情况下你将看到如下输出:

Server is running at http://127.0.0.1:3000 Try http://127.0.0.1:3000/ping

npm start背后发生了什么

从示例工程的 package.json 可以看到,start脚本的定义是:

"prestart": "npm run rebuild", "start": "node ."

也就是说npm start会先执行rebuild(即npm run clean && npm run build,先用lb-tsc把 TypeScript 编译到dist目录),再执行node .直接运行编译产物。如果你的应用是在教程脚手架阶段由lb4 app soap-calculator生成的,依赖包已经自动安装完毕,无需额外执行npm install。

启动日志从哪来

"Server is running at http://127.0.0.1:3000" 这一行并非写死在代码里,而是由入口文件在应用启动后动态打印的。查看 src/index.ts:

export async function main(options: ApplicationConfig = {}) { const app = new SoapCalculatorApplication(options); await app.boot(); await app.start(); const url = app.restServer.url; console.log(`Server is running at ${url}`); return app; }

app.restServer.url是 RestServer 暴露的只读属性,其值由底层HttpServer根据协议、主机与端口实时拼装。相关实现见 packages/http-server/src/http-server.ts:

public get url(): string { ... if ([6, 'IPv6'].includes(this._address.family)) { if (host === '::') host = '::1'; host = `[${host}]`; } else if (host === '0.0.0.0') { host = '127.0.0.1'; } return `${this._protocol}://${host}:${this.port}`; }

注意这里有一个容易被忽略的细节:当服务绑定到0.0.0.0(即监听所有网卡接口)时,url会将其归一化为127.0.0.1输出。因此即使你的进程实际监听在所有接口上,启动日志中显示的地址也通常是127.0.0.1,这是正常的。

启动成功后,把浏览器指向http://127.0.0.1:3000/ping可以看到 LoopBack 4 的默认问候信息,说明 REST 服务器与默认路由都已就绪。完成验证后可以按Ctrl-C停止应用,继续后续步骤。


用 curl 测试 REST 端点

你可以用浏览器或任意 HTTP 客户端(如 curl)来测试应用。重要前提:本教程使用的 SOAP Web 服务是部署在云端的(https://calculator-webservice.mybluemix.net/calculator),因此测试时必须保证机器已连接互联网,否则请求会在调用远端服务时失败。

执行:

curl http://localhost:3000/add/50/50

你会看到响应体中包含两个属性:result(JSON 格式)与envelope(XML 格式):

{"result":{"value":100},"envelope":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"http://wsdl.example.org/\"><SOAP-ENV:Body><ns1:AddResponse><AddResult>100</AddResult></ns1:AddResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

理解result与envelope两个属性

  • result:SOAP 响应经过loopback-connector-soap解析后生成的 JSON 结构化结果,形如{"value": 100}。如果客户端只处理 JSON,只需关注这个属性;你可以按惯例用result.value直接取到100。
  • envelope:远端 SOAP Web 服务返回的原始 XML SOAP 信封。它保留了完整的Envelope → Body → AddResponse → AddResult层级。如果你需要以 XML 格式处理响应(例如对接遗留系统、审计留痕),这个属性会非常有用。

这种"结构化结果 + 原始信封"同时返回的设计,正是 LoopBack 4 服务代理层对 XML→JSON 转换"透明化"的体现:作为开发者,你既不必手写 XML 解析,也随时可以拿到原始报文。

四个端点的完整测试

控制器在 src/controllers/calculator.controller.ts 中定义了四个端点,全部要求两个整型路径参数{intA}与{intB}:

REST 端点SOAP 操作示例期望结果result.value
GET /add/{intA}/{intB}Add/add/50/50100
GET /subtract/{intA}/{intB}Subtract/subtract/100/2575
GET /multiply/{intA}/{intB}Multiply/multiply/25/375
GET /divide/{intA}/{intB}Divide/divide/50/225

可以依次用 curl 验证:

curl http://localhost:3000/add/50/50 curl http://localhost:3000/subtract/100/25 curl http://localhost:3000/multiply/25/3 curl http://localhost:3000/divide/50/2

参数校验与异常行为

得益于控制器上的@param.path.integer('intA')装饰器(参见 calculator.controller.ts),LoopBack 4 会在进入业务逻辑前自动校验路径参数的数据类型,并配合前置条件检查返回规范的 HTTP 状态码:

  • 除零保护:divide方法内部对intB === 0抛出了HttpErrors.PreconditionFailed,即412 Precondition Failed,响应信息为Cannot divide by zero;
  • 非整数参数:传入2.5这类非整数值会被参数校验拦截,返回400 Bad Request;
  • 缺少必需参数:访问/divide/或/multiply/(缺少参数)会命中路由未匹配,返回404 Not Found。

这些行为在示例工程的验收测试 src/tests/acceptance/application.acceptance.ts 中有完整覆盖,例如:

it('rejects division by zero with 412 error', async () => { await client.get('/divide/20/0').expect(412); }); it('returns 400 when the "/add" receives a non integer parameter', async () => { await client.get('/add/5/1.2').expect(400); });

值得注意的是,由于示例依赖的云端 SOAP 服务目前已不可用,该验收测试文件与集成测试 calculator.service.integration.ts 都使用了describe.skip跳过执行(源码中留有FIXME注释说明 WSDL 端点已下线)。集成测试本身则展示了不经过 HTTP、直接调用服务代理层验证四则运算的写法,例如:

it('adds two numbers', async () => { const response = await calculatorService.add(<CalculatorParameters>{ intA: 50, intB: 2, }); expect(response.result.value).to.deepEqual(52); });

如果你的环境可以访问到该外部服务,可移除describe.skip后运行npm test自行验证。


底层原理:SOAP→REST 的透明转换是如何发生的

测试之所以一条curl就能拿到 JSON 结果,是因为前面教程搭建的"数据源 + 服务代理 + 控制器"三层结构完成了 XML↔JSON 的透明转换:

  1. 数据源(calculator.datasource.ts)配置了 SOAP 连接器、url、wsdl,以及operations映射(把CalculatorService服务的CalculatorPort端口上的Add/Subtract/Multiply/Divide四个操作分别绑定到 Node.js 方法名);
  2. 服务代理(calculator.service.ts)中的CalculatorServiceProvider注入数据源,并通过getService(this.dataSource)从@loopback/service-proxy生成类型化的服务客户端;
  3. 控制器把 REST 路由参数intA、intB组装成CalculatorParameters传给服务方法,远端 SOAP 返回的 XML 被连接器解析后同时以result(JSON)与envelope(原始 XML)两种形态返回给客户端。

因此对前端客户端而言,访问/add/50/50与访问一个普通 REST API 没有任何区别;SOAP 协议细节、XML 序列化与反序列化都被隔离在服务代理层之下。这也是 LoopBack 4 集成遗留 SOAP 系统的典型模式:可以在单个应用或多个微服务中同时接入若干 legacy SOAP Web 服务,架构取舍完全由你的系统设计决定。


修改监听地址与端口号

有时你需要限制应用绑定的 IP 地址以及监听端口。教程推荐的方式是在src/application.ts的构造函数中、super(options);语句之前,用Object.assign合并默认配置:

options = Object.assign( {}, { rest: { url: '127.0.0.1', port: 3000, }, }, options, );

注意:合并顺序决定了优先级——后出现的options会覆盖默认值,因此外部传入的配置(例如测试环境或部署时注入的配置)仍然具有最高优先级;而当你什么都不传时,则回退到这里设置的127.0.0.1:3000。示例工程中的构造函数结构见 src/application.ts,其中SoapCalculatorApplication是通过BootMixin(ServiceMixin(RepositoryMixin(RestApplication)))组合而成的。

配置项在源码中的真实语义

从 packages/rest/src/rest.server.ts 可以看到,RestServerConfig = RestServerOptions & HttpServerOptions,其默认配置为:

const DEFAULT_CONFIG: RestServerResolvedConfig = { port: 3000, openApiSpec: {}, apiExplorer: {}, cors: { origin: '*', methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', preflightContinue: false, optionsSuccessStatus: 204, maxAge: 86400, credentials: true, }, expressSettings: {}, router: {}, listenOnStart: true, };

要点说明:

  • port默认是 3000,且0是合法值——端口为0时系统会分配一个随机空闲端口,这在测试中非常常用(见验收测试里rest: {host: '127.0.0.1', port: 0}的写法);
  • host默认为undefined,此时 HTTP 服务器会监听所有网络接口(对应HttpServer的默认行为,见 packages/http-server/src/http-server.ts);
  • Object.assign中使用的url键对应HttpServerOptions中的host语义(表示绑定地址,并非完整 URL 字符串);从代码结构看,教程示例以url命名是沿用了早期文档的习惯性写法。

更工程化的替代方案:环境变量

如果不想改代码,示例工程的入口还提供了基于环境变量的配置方式(src/index.ts):

const config = { rest: { port: +(process.env.PORT ?? 3000), host: process.env.HOST ?? 'localhost', openApiSpec: { // useful when used with OpenAPI-to-GraphQL to locate your application setServersFromRequest: true, }, }, };

也就是说,直接设置环境变量即可覆盖监听行为:

PORT=8080 HOST=0.0.0.0 npm start

这与在application.ts中做Object.assign的效果等价,且无需重新编译。两种方式可以根据部署场景(容器、本地调试、测试环境)灵活选用。


常见问题排查

  • 启动日志显示Server is running at ...但 curl 连不上:检查防火墙与绑定地址。若host设为127.0.0.1,则只能从本机访问;局域网或容器外访问需要绑定0.0.0.0。
  • curl 请求长时间无响应或报错:本教程的 SOAP 服务托管在云端,请先确认网络连通性;云端服务可能处于休眠状态,首次请求会有一定唤醒延迟。
  • /divide/20/0返回 412 而非计算结果:这是控制器中前置条件检查的预期行为(Cannot divide by zero),属于正常防御性设计。
  • 端口被占用:LoopBack 4 在端口被占用时会在启动阶段报错,此时可通过PORT环境变量或Object.assign更换端口后重试。

参考与后续路径

  • 本教程前一步骤:Add a Controller(控制器与四个 REST 端点的完整实现)
  • 教程系列入口:SOAP Web Service Overview
  • 完整可运行示例:examples/soap-calculator(含README.md与接受/集成测试)
  • 服务代理实现:@loopback/service-proxy 示例中的 getService
  • 底层监听实现:packages/http-server/src/http-server.ts、packages/rest/src/rest.server.ts

至此,你已经完成了从 SOAP Web 服务概览到运行测试的完整 LoopBack 4 集成之旅:应用可以通过 REST 端点对外提供四则运算能力,JSON 客户端与 XML 客户端都能各取所需,而监听地址与端口也完全处于你的掌控之中。

  • 后端
  • 微服务

【免费下载链接】loopback-next

LoopBack makes it easy to build modern API applications that require complex integrations.

项目地址:https://gitcode.com/gh_mirrors/lo/loopback-next
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询