Node.js SOAP服务器:如何从Promise异步操作返回正确数据?
Node.js SOAP服务异步Promise返回数据问题解决
问题场景
基于Node.js搭建的SOAP服务器,调用异步Promise函数操作Oracle数据库,尝试用XMLWriter构建包含查询结果的XML响应,但客户端仅收到空的<result/>元素,无法获取数据库查询添加的子元素。核心代码如下:
const soap = require('soap'); const http = require('http'); const XMLWriter = require('xml-writer'); const service = { ImpDispatcherService: { ImpDispatcher: { performTest: function (args) { const xw = new XMLWriter(true); xw.startDocument(); xw.startElement('result'); queryDatabase(args.parameter1, xw).then(success => { console.log(success); xw.endDocument(); console.log(xw.toString()); // -> prints the full XML-File }); return { testResult: xw.toString() }; } } } }; var server = http.createServer((request, response) => { response.end('404: Not Found: ' + request.url); }); // Create the SOAP server const xml = require('fs').readFileSync(`${__dirname}/ImpDispatcherService.wsdl`, 'utf8'); var server = http.createServer((request, response) => { response.end('404: Not Found: ' + request.url); }); server.listen(8000, 'localhost'); soap.listen(server, '/imp', service, xml, () => { logger.info('Server initialized'); }); async function queryDatabase(pars) { const oracledb = require('oracledb'); const connection = await oracledb.getConnection(db); const result = await connection.execute(`BEGIN :ret := getResult(${pars}); END;`, {ret: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR } }); let row; while (row = await result.outBinds.ret.getRow()) { xw.writeElement('tag', row.blabla); } return true; }
问题原因
performTest方法调用queryDatabase后直接返回xw.toString(),此时异步数据库查询尚未完成,XMLWriter还未添加任何子元素,因此返回的是仅包含空<result/>标签的XML字符串。
解决方案
将performTest改为异步函数,等待queryDatabase执行完成后再构建并返回响应数据,同时修正queryDatabase的参数传递问题:
修改后的核心代码
const service = { ImpDispatcherService: { ImpDispatcher: { // 改为async函数,支持await异步操作 performTest: async function (args) { const xw = new XMLWriter(true); xw.startDocument(); xw.startElement('result'); // 等待数据库查询完成再继续 await queryDatabase(args.parameter1, xw); xw.endDocument(); return { testResult: xw.toString() }; } } } }; // 修正queryDatabase,接收xw参数并完成数据库操作 async function queryDatabase(pars, xw) { let connection; try { const oracledb = require('oracledb'); connection = await oracledb.getConnection(db); const result = await connection.execute(`BEGIN :ret := getResult(${pars}); END;`, {ret: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR } }); let row; while (row = await result.outBinds.ret.getRow()) { xw.writeElement('tag', row.blabla); } // 关闭数据库游标 await result.outBinds.ret.close(); } finally { // 确保数据库连接关闭,避免资源泄漏 if (connection) { await connection.close(); } } return true; }
关键修改点
- 将
performTest声明为async函数,使用await等待queryDatabase执行完毕,保证XMLWriter完成所有子元素写入后再返回结果。 - 为
queryDatabase补充xw参数,确保能正确向XMLWriter添加数据库查询到的子元素。 - 添加
try/finally块,确保数据库连接和游标在操作完成后关闭,避免资源泄漏。 - 移除原代码中重复定义的
http.createServer实例。
完整修改后代码
const soap = require('soap'); const http = require('http'); const XMLWriter = require('xml-writer'); const oracledb = require('oracledb'); // 数据库配置,需根据实际情况填写 const db = { user: 'your_db_user', password: 'your_db_password', connectString: 'your_db_connect_string' }; const service = { ImpDispatcherService: { ImpDispatcher: { performTest: async function (args) { const xw = new XMLWriter(true); xw.startDocument(); xw.startElement('result'); await queryDatabase(args.parameter1, xw); xw.endDocument(); return { testResult: xw.toString() }; } } } }; // 创建HTTP服务器 const server = http.createServer((request, response) => { response.end('404: Not Found: ' + request.url); }); // 读取WSDL文件 const xml = require('fs').readFileSync(`${__dirname}/ImpDispatcherService.wsdl`, 'utf8'); // 启动服务器并监听SOAP请求 server.listen(8000, 'localhost'); soap.listen(server, '/imp', service, xml, () => { console.info('Server initialized'); }); async function queryDatabase(pars, xw) { let connection; try { connection = await oracledb.getConnection(db); const result = await connection.execute(`BEGIN :ret := getResult(${pars}); END;`, {ret: { dir: oracledb.BIND_OUT, type: oracledb.CURSOR } }); let row; while (row = await result.outBinds.ret.getRow()) { xw.writeElement('tag', row.blabla); } await result.outBinds.ret.close(); } catch (err) { console.error('Database query error:', err); throw err; // 抛出错误让SOAP框架处理异常响应 } finally { if (connection) { await connection.close(); } } return true; }
内容的提问来源于stack exchange,提问作者Wernfried Domscheit
相关产品推荐
相关产品推荐

