node-soap 将命名空间添加到信封
node-soap adding namespace to envelope
我正在尝试使用此 soap 服务:http://testws.truckstop.com:8080/v13/Posting/LoadPosting.svc?singleWsdl 和 node-soap,但客户端正在破坏命名空间,我一直无法找到有效的解决方案。
我认为答案是要么向 soap 信封添加命名空间,要么覆盖 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
,但命名空间未在信封中引用。
我已尝试更新客户端以将命名空间添加为 suggested here:
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>
但是远程服务器不理解。
感谢阅读!
This answer was correct all along
由于自动完成和类似字段,它对我不起作用
client.wsdl.xmlnInEnvelope = client.wsdl._xmlnsMap();
应该是:
client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap();
我遗漏了一个 s
并设置了 xmlnInEnvelope 而不是 xmlnsInEvelope
已经有几年了,但我 运行 有类似的需求,需要将自定义属性添加到 soap 信封,并想提供一个替代方案。
在撰写本文时,_xmlnsMap()
是 WSDL class 上的 private method,因此您可以自行承担使用它的风险。我总是将私有方法视为开发人员更改的对象,而不通知库使用者,所以我想找到另一种方法并证明它是可能的。
TL;DR - 创建您自己的 WSDL class 实例并将其传递给您自己的客户端 class 实例。
- 使用 open_wsdl 方法引入您的 WSDL
- 使用回调在串联字符串中构建您自己的自定义属性。
- 将属性分配给 public
xmlnsInEnvelope
属性.
- return 更新后的 WSDL 实例(我使用了 promise)。
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 实例和 return 创建一个新的客户端实例。
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
类型,如果您打算升级,使用起来更安全。
我正在尝试使用此 soap 服务:http://testws.truckstop.com:8080/v13/Posting/LoadPosting.svc?singleWsdl 和 node-soap,但客户端正在破坏命名空间,我一直无法找到有效的解决方案。
我认为答案是要么向 soap 信封添加命名空间,要么覆盖 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
,但命名空间未在信封中引用。
我已尝试更新客户端以将命名空间添加为 suggested here:
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>
但是远程服务器不理解。
感谢阅读!
This answer was correct all along
由于自动完成和类似字段,它对我不起作用
client.wsdl.xmlnInEnvelope = client.wsdl._xmlnsMap();
应该是:
client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap();
我遗漏了一个 s
并设置了 xmlnInEnvelope 而不是 xmlnsInEvelope
已经有几年了,但我 运行 有类似的需求,需要将自定义属性添加到 soap 信封,并想提供一个替代方案。
在撰写本文时,_xmlnsMap()
是 WSDL class 上的 private method,因此您可以自行承担使用它的风险。我总是将私有方法视为开发人员更改的对象,而不通知库使用者,所以我想找到另一种方法并证明它是可能的。
TL;DR - 创建您自己的 WSDL class 实例并将其传递给您自己的客户端 class 实例。
- 使用 open_wsdl 方法引入您的 WSDL
- 使用回调在串联字符串中构建您自己的自定义属性。
- 将属性分配给 public
xmlnsInEnvelope
属性. - return 更新后的 WSDL 实例(我使用了 promise)。
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 实例和 return 创建一个新的客户端实例。
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
类型,如果您打算升级,使用起来更安全。