node-soap добавляет пространство имен в конверт
Я пытаюсь использовать этот сервис мыла: http://testws.truckstop.com:8080/v13/Posting/LoadPosting.svc?singleWsdl с помощью node-soap, но клиент искажает пространства имен, и мне не удалось найти рабочий раствор.
Я считаю, что ответ заключается в том, чтобы либо добавить пространство имен в мыльный конверт, либо перезаписать мыльный конверт.
С помощью Soap UI
запрос должен выглядеть так:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:v11="http://webservices.truckstop.com/v11"
xmlns:web="http://schemas.datacontract.org/2004/07/WebServices">
<soapenv:Header/>
<soapenv:Body>
<v11:GetLoads>
<v11:listRequest>
<web:IntegrationId>integrationId</web:IntegrationId>
<web:Password>password</web:Password>
<web:UserName>username</web:UserName>
</v11:listRequest>
</v11:GetLoads>
</soapenv:Body>
</soapenv:Envelope>
Тем не менее, когда я делаю:
client = soap.createClient(url);
let query = {
listRequest: {
Password: password,
UserName: username,
IntegrationId: integrationId
}
};
let results = client.GetLoads(query);
Клиент генерирует этот xml:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:tns="http://webservices.truckstop.com/v11"
xmlns:q1="http://schemas.datacontract.org/2004/07/WebServices.Posting"
xmlns:q2="http://schemas.datacontract.org/2004/07/WebServices.Objects"
xmlns:q3="http://schemas.datacontract.org/2004/07/WebServices.Posting"
xmlns:q4="http://schemas.datacontract.org/2004/07/WebServices.Objects"
xmlns:q5="http://schemas.datacontract.org/2004/07/WebServices.Posting"
xmlns:q6="http://schemas.datacontract.org/2004/07/WebServices.Objects"
xmlns:q7="http://schemas.datacontract.org/2004/07/WebServices.Posting"
xmlns:q8="http://schemas.datacontract.org/2004/07/WebServices.Objects"
xmlns:q9="http://schemas.datacontract.org/2004/07/WebServices.Posting"
xmlns:q10="http://schemas.datacontract.org/2004/07/WebServices.Objects"
xmlns:q11="http://schemas.datacontract.org/2004/07/WebServices.Posting"
xmlns:q12="http://schemas.datacontract.org/2004/07/WebServices.Objects">
<soap:Body>
<GetLoads xmlns="http://webservices.truckstop.com/v11">
<listRequest>
<ns1:IntegrationId>integrationId</ns1:IntegrationId>
<ns1:Password>password</ns1:Password>
<ns1:UserName>usernam</ns1:UserName>
</listRequest>
</GetLoads>
</soap:Body>
</soap:Envelope>
Это не удается, потому что IntegrationId
, Password
а также UserName
необходимость http://schemas.datacontract.org/2004/07/WebServices
, но пространство имен не указано в конверте.
Я попытался обновить клиент, чтобы добавить пространство имен, как предложено здесь:
client.wsdl.definitions.xmlns.ns1 = "http://schemas.datacontract.org/2004/07/WebServices";
client.wsdl.xmlnInEnvelope = client.wsdl._xmlnsMap();
Я могу видеть пространство имен в client.wsdl.xmlnInEnvelope
, но это не похоже на изменение фактического сгенерированного XML.
Есть ли еще один шаг, необходимый для обновления клиента для использования обновленного конверта?
Я также попытался переопределить корневой элемент, как показано здесь:
var wsdlOptions = {
//namespaceArrayElements: "xmlns:ns1=http://schemas.datacontract.org/2004/07/WebServices"
"overrideRootElement": {
"namespace": "xmlns:tns",
"xmlnsAttributes": [{
"name": "xmlns:tns",
"value": "http://webservices.truckstop.com/v11"
}, {
"name": "xmlns:ns1",
"value": "http://schemas.datacontract.org/2004/07/WebServices"
}]
}
};
this.loadPostClient = soap.createClient(this.tsConfig.loadPostUrl, wsdlOptions);
Это меняет корневой элемент тела:
<soap:Body>
<xmlns:tns:GetLoads
xmlns:tns="http://webservices.truckstop.com/v11"
xmlns:ns1="http://schemas.datacontract.org/2004/07/WebServices">
<listRequest>
<ns1:IntegrationId>integrationId</ns1:IntegrationId>
<ns1:Password>password</ns1:Password>
<ns1:UserName>username</ns1:UserName>
</listRequest>
</xmlns:tns:GetLoads>
</soap:Body>
Но удаленный сервер не понимает.
Спасибо за чтение!
2 ответа
Этот ответ был правильным с самого начала
Это не работает для меня из-за автозаполнения и аналогичных полей
client.wsdl.xmlnInEnvelope = client.wsdl._xmlnsMap();
Должно было:
client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap();
Я оставил s
и устанавливал xmlnInEnvelope вместо xmlns InEvelope
Прошло несколько лет, но я столкнулся с аналогичной необходимостью добавления пользовательских атрибутов в мыльный конверт и хотел дать альтернативу.
На момент написания этой
_xmlnsMap()
— это закрытый метод класса WSDL, поэтому вы можете использовать его на свой страх и риск. Я всегда рассматриваю частные методы как подлежащие изменению со стороны разработчика без какого-либо уведомления пользователей библиотеки, поэтому я хотел найти другой способ, и оказалось, что это возможно.
TL;DR — Создайте свой собственный экземпляр класса WSDL и передайте его своему собственному экземпляру класса Client.
- Используйте метод open_wsdl , чтобы добавить свой WSDL .
- Используйте обратный вызов для создания собственных настраиваемых атрибутов в объединенной строке.
- Назначьте атрибуты для общественности
xmlnsInEnvelope
свойство. - вернуть обновленный экземпляр WSDL (я использовал обещание).
const fetchWSDL = new Promise<WSDL>((resolve, reject) => {
// method that returns a WSDL instance from a url/file path
open_wsdl(this.wsdl, (err: any, wsdl?: WSDL) => {
// Build custom attributes
if (wsdl && wsdl.definitions.xmlns) {
const xmlns: { [key: string]: string } = {
[your namespaces]: 'values',
};
// turn your custom attributes map into a single concatenated string
let str = '';
for (const alias in xmlns) {
const ns = xmlns[alias];
str += ' xmlns:' + alias + '="' + ns + '"';
}
// Leverage public attribute on WSDL instance to apply our custom attributes
wsdl.xmlnsInEnvelope = str;
resolve(wsdl);
}
reject(err);
});
});
Используйте обновленный экземпляр WSDL для создания собственного клиента.
Обратите внимание
createClient
метод является просто удобной оболочкой для создания экземпляра WSDL и возврата нового экземпляра Client.
const ModifiedWSDL = await fetchWSDL;
// Create client with our modified WSDL instance
this.client = new Client(ModifiedWSDL)
// adjust your Client instance as needed
Немного больше кода, чем в OP, но, надеюсь, больше соответствует
node-soap
типы и безопаснее использовать, если вы планируете обновить.