You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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; }

关键修改说明

  1. 新增checkSoapError函数:解析转换后的JSON结构,检查SOAP Fault节点(需根据你的SOAP服务实际命名空间和节点路径调整),如果检测到错误则直接生成自定义错误响应。
  2. 修改validateEspecific函数:在处理正常业务逻辑前,先调用checkSoapError函数,确保SOAP错误被优先处理。
  3. 优化错误捕获:在transform.xpath的错误回调中,替换直接输出错误为调用generateResponseMessage返回自定义解析错误。
  4. 移除不可靠的传输头依赖:放弃使用X-Backside-Transport头判断错误,改为直接解析响应体内容,更适配SOAP服务用HTTP 200返回错误的场景。

内容的提问来源于stack exchange,提问作者Larry Tena Contreras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:37:08