Node.js中用soap npm调用SOAP API遇信封转换失败问题求助
解决Node.js soap包调用Sabre SSSAdvShopRQ接口缺少Header的问题
调用Sabre的SSSAdvShopRQ接口时,使用Node.js的soap npm包构建参数对象后,无法转换为正确的SOAP请求信封,返回错误:
soap-env:Fault soap-env:Client.InvalidEbXmlMessage Missing <soap-env:Header> in <soap-env:Envelope> javax.xml.soap.SOAPException: Missing <soap-env:Header> in <soap-env:Envelope>
原app.js代码
var soap = require('soap'); const express = require('express'); const bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.json()); const url = 'https://files.developer.sabre.com/wsdl/sabreXML1.0.00/shopping/SSSAdvShopRQ_v5-4-0.wsdl'; let params = { Envelope: { Header: { Action:"SSSAdvShopRQ", Security: { BinarySecurityToken: "Token" }, MessageHeader: { From: { PartyId:[ "WebServiceClient"] }, To: { PartyId:[ "WebServiceSupplier"] }, CPAId: "ET", ConversationId: "TestSession", Service: "SSSAdvShop", Action: "SSSAdvShopRQ" }, }, Body: { OTA_AirLowFareSearchRQ: { POS: { Source: { RequestorID: { CompanyName: { Code: "SSW" }, Type: "1", ID: "1" }, PseudoCityCode: "ADD" } }, OriginDestinationInformation: [ { DepartureDateTime: "2023-01-25T00:00:00", OriginLocation: { LocationCode: "ADD" }, DestinationLocation: { LocationCode: "DXB" }, TPA_Extensions: "", RPH: "1" }, { DepartureDateTime: "2023-01-31T00:00:00", OriginLocation: { LocationCode: "DXB" }, DestinationLocation: { LocationCode: "SEA" }, TPA_Extensions: "", RPH: "2" } ], TravelPreferences: "", TravelerInfoSummary: { AirTravelerAvail: { PassengerTypeQuantity: { Code: "ADT", Quantity: "1" } }, PriceRequestInformation: { TPA_Extensions: { Indicators: { RetainFare: { Ind: "true" }, MinMaxStay: { Ind: "true" }, RefundPenalty: { Ind: "true" }, ResTicketing: { Ind: "true" }, TravelPolicy: { Ind: "true" } }, PointOfSaleOverride: { Code: "ADD" } }, CurrencyCode: "ETB" } }, TPA_Extensions: { IntelliSellTransaction: { RequestType: { Name: "ADVBRD" }, ServiceTag: { Name: "ET" } } }, Version: "5.4.0" }, } } }; app.get('/', function (req, res) { soap.createClient(url, function (err, client) { client.SSSAdvShopRQAsync(params, function (err, response) { console.log(response.data); res.setHeader('Content-Type', 'application/json'); res.status(200).send(response.data); }); }); }); app.listen(3000, () => { console.log("Server started at port 3000"); });
错误响应
soap-env:Fault
soap-env:Client.InvalidEbXmlMessage
Missing soap-env:Header in soap-env:Envelopejavax.xml.soap.SOAPException: Missing soap-env:Header in soap-env:Envelope
</soap-env:Fault>
解决方法
问题出在soap包的用法错误:soap包会自动生成SOAP Envelope结构,不需要手动传入整个Envelope对象,否则包无法正确识别Header部分。正确做法是拆分Header和业务参数,单独设置Header,只将业务数据作为接口参数传入。
修改后的代码
var soap = require('soap'); const express = require('express'); const bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.json()); const url = 'https://files.developer.sabre.com/wsdl/sabreXML1.0.00/shopping/SSSAdvShopRQ_v5-4-0.wsdl'; // 单独提取Header内容 const soapHeader = { Action:"SSSAdvShopRQ", Security: { BinarySecurityToken: "Token" }, MessageHeader: { From: { PartyId:[ "WebServiceClient"] }, To: { PartyId:[ "WebServiceSupplier"] }, CPAId: "ET", ConversationId: "TestSession", Service: "SSSAdvShop", Action: "SSSAdvShopRQ" }, }; // 业务参数只保留Body中的OTA_AirLowFareSearchRQ内容 let params = { OTA_AirLowFareSearchRQ: { POS: { Source: { RequestorID: { CompanyName: { Code: "SSW" }, Type: "1", ID: "1" }, PseudoCityCode: "ADD" } }, OriginDestinationInformation: [ { DepartureDateTime: "2023-01-25T00:00:00", OriginLocation: { LocationCode: "ADD" }, DestinationLocation: { LocationCode: "DXB" }, TPA_Extensions: "", RPH: "1" }, { DepartureDateTime: "2023-01-31T00:00:00", OriginLocation: { LocationCode: "DXB" }, DestinationLocation: { LocationCode: "SEA" }, TPA_Extensions: "", RPH: "2" } ], TravelPreferences: "", TravelerInfoSummary: { AirTravelerAvail: { PassengerTypeQuantity: { Code: "ADT", Quantity: "1" } }, PriceRequestInformation: { TPA_Extensions: { Indicators: { RetainFare: { Ind: "true" }, MinMaxStay: { Ind: "true" }, RefundPenalty: { Ind: "true" }, ResTicketing: { Ind: "true" }, TravelPolicy: { Ind: "true" } }, PointOfSaleOverride: { Code: "ADD" } }, CurrencyCode: "ETB" } }, TPA_Extensions: { IntelliSellTransaction: { RequestType: { Name: "ADVBRD" }, ServiceTag: { Name: "ET" } } }, Version: "5.4.0" } }; app.get('/', function (req, res) { soap.createClient(url, function (err, client) { // 添加SOAP Header client.addSoapHeader(soapHeader); // 只传入业务参数 client.SSSAdvShopRQAsync(params, function (err, response) { if (err) { console.error(err); res.status(500).send(err); return; } console.log(response.data); res.setHeader('Content-Type', 'application/json'); res.status(200).send(response.data); }); }); }); app.listen(3000, () => { console.log("Server started at port 3000"); });
关键改动说明
- 将Header内容从params中拆分出来,通过
client.addSoapHeader()方法单独设置,确保soap包正确将其放入SOAP Envelope的Header部分。 - params只保留业务请求体(OTA_AirLowFareSearchRQ),这是
SSSAdvShopRQAsync方法需要的参数,soap包会自动将其包裹到Envelope的Body中。 - 添加了错误处理,方便排查调用中的其他问题。
内容的提问来源于stack exchange,提问作者Samuel Wakuma
相关产品推荐
相关产品推荐

