如何在IBM App Connect中用GatewayScript控制SOAP错误(HTTP 200)返回消息
解决IBM App Connect中SOAP服务HTTP 200状态下的自定义错误返回问题
问题场景
在IBM App Connect环境中调用后端SOAP服务并转换为JSON格式,正常场景无异常,但错误场景(后端返回HTTP 200但包含SOAP错误内容)时,当前代码返回通用错误消息,需要控制这类错误返回自定义消息。尝试使用X-Backside-Transport请求头未成功。
解决方案
核心思路是直接解析SOAP响应体中的错误节点,替代仅依赖HTTP状态码或传输头的判断方式,具体实现如下:
修改后的完整GatewayScript代码
var apim = require('apim'); // IMPORT const transform = require('transform'); const converter = require('json-xml-converter'); // CONSTANTES const HTTP_CODE_FUNCTIONAL = 209; const HTTP_CODE_OK = 200; const HTTP_CODE_500 = 500; const HTTP_MESSAGE_500 = 'Internal Server Error'; const codeErrors = [500, 403, 503, 404]; // VARIABLES let bodyProvider = apim.getvariable('message.body'); let httpCode = apim.getvariable('message.status.code'); // SERVICE VARIABLES let tagBackend = '//xmlns:GetClienteObservadosOFACR1SelResponse'; let tagNamespace = 'http://tempuri.org/'; let dataType = 'xml'; let nsVar = 'xmlns'; // INIT VALIDATE PROCCESS manageResponse(httpCode, bodyProvider, dataType, tagBackend, nsVar, tagNamespace); /*---------------------------- Operation section ----------------------------*/ // 检查SOAP错误节点 function checkSoapError(sJson) { // 根据你的SOAP服务实际命名空间和Fault节点路径调整 // 示例:假设SOAP Fault在Envelope.Body.Fault下 if (sJson['soap:Envelope'] && sJson['soap:Envelope']['soap:Body'] && sJson['soap:Envelope']['soap:Body']['soap:Fault']) { let fault = sJson['soap:Envelope']['soap:Body']['soap:Fault']; let errorMsg = fault['faultstring'] || 'SOAP服务调用错误'; // 返回自定义错误响应 generateResponseMessage(HTTP_CODE_500, HTTP_MESSAGE_500, '502', errorMsg, 'SOAP_ERROR', errorMsg, null); return true; } return false; } // Especific function: Validate items ok function validateEspecific(sJson) { // 先检查SOAP错误 if (checkSoapError(sJson)) { return; } let okSrvCods = ['OK']; let flagMapInGateway = true; let texto = ''; if (typeof sJson.GetClienteObservadosOFACR1SelResponse.GetClienteObservadosOFACR1SelResult.NewDataSet.Datos == undefined || sJson.GetClienteObservadosOFACR1SelResponse.GetClienteObservadosOFACR1SelResult.NewDataSet.Datos == null || sJson.GetClienteObservadosOFACR1SelResponse.GetClienteObservadosOFACR1SelResult.NewDataSet.Datos == '') { texto += '{ "blackListFlag": "false"}'; } else { texto += '{ "blackListFlag": "true"}'; } generateResponseMessage(200, 'OK', '0', 'EJECUCION CON EXITO', '0000', 'OK', texto); } // Especific function: Create response 200 function mapJsonOK(codError, msgError, respuesta) { let rsMessage = '{ "sequenceId": "' + respuesta.trim() + '"}'; generateResponseMessage(200, 'OK', '0', 'EJECUCION CON EXITO', codError, msgError, rsMessage); } /*---------------------------- Operation section ----------------------------*/ /*------------------------------ Free section -------------------------------*/ function defaultVal(field, def) { field = typeof field !== 'undefined' && field != null && field != '' ? field : def; return field; } /*------------------------------ Free section -------------------------------*/ /*-------------------------- Framework IFX section --------------------------*/ //Generic function: Manage response function manageResponse(httpCode, bodyProvider, dataType, tagBackend, nsVar, tagNamespace){ if (codeErrors.includes(httpCode)){ // Separar segun codigo generateResponseMessage(HTTP_CODE_500, HTTP_MESSAGE_500, '302','An error occurred trying to invoke external services.'); } else if(200 == httpCode) { if(bodyProvider) { validateAndTransformBody(dataType, bodyProvider, tagBackend, nsVar, tagNamespace); } else { generateResponseMessage(HTTP_CODE_500, HTTP_MESSAGE_500, '302','An error occurred trying to invoke external services.'); } } else { // Codigo HTTP no conocido, genera respuesta generica generateResponseMessage(HTTP_CODE_500, HTTP_MESSAGE_500, '302','An error occurred trying to invoke external services.'); } } // Generic function: Validate dataType and transform body function validateAndTransformBody(dataType, bodyProvider, tagBackend, nsVar, tagNamespace) { if(dataType == 'xml' ) { let options = { 'expression': '//tns1:GetClienteObservadosOFACR1SelResponse', 'xmldom': bodyProvider, 'namespace': { 'tns1' : 'http://tempuri.org/' } }; let option = { omitXmlDeclaration: true }; transform.xpath(options, function(err, xmlNodeList) { if (err) { generateResponseMessage(HTTP_CODE_500, HTTP_MESSAGE_500, '301','解析SOAP响应失败'); } else { let output = XML.stringify(option, xmlNodeList); let xml = XML.parse(output); let sJson = converter.toJSON('badgerfish', xml); validateEspecific(sJson); } }); } else { validateEspecific(bodyProvider); } } // Generic function: Propagate to Map Policy function skipToMap(flag) { apim.setvariable('message.headers.skip', true); } // Generic function: Responde cabecera de error IFX function generateResponseMessage(codeHttp, reasonHttp, busResponseCode, busResponseMessage, srvResponseCode, srvResponseMessage, responseMessage){ let globalTransaccionId = apim.getvariable('message.headers.X-Global-Transaction-ID'); apim.setvariable('message.headers','','clear'); apim.setvariable('message.body','','clear'); apim.setvariable('message.headers.busResponseCode', busResponseCode); apim.setvariable('message.headers.busResponseMessage', busResponseMessage); apim.setvariable('message.headers.srvResponseCode', srvResponseCode); apim.setvariable('message.headers.srvResponseMessage', srvResponseMessage); apim.setvariable('message.headers.X-Global-Transaction-ID', globalTransaccionId); if(responseMessage != null){ apim.setvariable('message.body', responseMessage); } apim.setvariable('message.status.code', codeHttp); apim.setvariable('message.status.reason', reasonHttp); apim.output('application/json'); } /*-------------------------- Framework IFX section --------------------------*/ function pad(n, width, z) { z = z || '0'; n = n + ''; return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; }
关键修改说明
- 新增
checkSoapError函数:解析转换后的JSON结构,检查SOAP Fault节点(需根据你的SOAP服务实际命名空间和节点路径调整),如果检测到错误则直接生成自定义错误响应。 - 修改
validateEspecific函数:在处理正常业务逻辑前,先调用checkSoapError函数,确保SOAP错误被优先处理。 - 优化错误捕获:在
transform.xpath的错误回调中,替换直接输出错误为调用generateResponseMessage返回自定义解析错误。 - 移除不可靠的传输头依赖:放弃使用
X-Backside-Transport头判断错误,改为直接解析响应体内容,更适配SOAP服务用HTTP 200返回错误的场景。
内容的提问来源于stack exchange,提问作者Larry Tena Contreras
相关产品推荐
相关产品推荐

