如何使用 Cloud Functions for Firebase 编写 SOAP 服务?
How to use Cloud Functions for Firebase to write a SOAP service?
我需要使用 firebase 函数实现 soap 网络服务。
我发现一个名为 soap-node soap-module-github 的模块看起来很有前途,因为它与 express 集成,firebase 说它使用 express 进行 http 调用,但问题是我不知道如何将该模块与 firebase 集成函数,因为 firebase 函数是客户端发出的 http 调用的处理程序,任何帮助都会非常有帮助。
这是我到目前为止成功创建的代码:
var fs = require('fs'),
soap = require('soap'),
express = require('express'),
lastReqAddress;
var server = express();
service = {
StockQuoteService: {
StockQuotePort: {
GetLastTradePrice: function (args, cb, soapHeader) {
if (soapHeader)
return {
price: soapHeader.SomeToken
};
if (args.tickerSymbol === 'trigger error') {
throw new Error('triggered server error');
} else if (args.tickerSymbol === 'Async') {
return cb({
price: 19.56
});
} else if (args.tickerSymbol === 'SOAP Fault v1.2') {
throw {
Fault: {
Code: {
Value: "soap:Sender",
Subcode: {
value: "rpc:BadArguments"
}
},
Reason: {
Text: "Processing Error"
}
}
};
} else if (args.tickerSymbol === 'SOAP Fault v1.1') {
throw {
Fault: {
faultcode: "soap:Client.BadArguments",
faultstring: "Error while processing arguments"
}
};
} else {
return {
price: 19.56
};
}
},
SetTradePrice: function (args, cb, soapHeader) {},
IsValidPrice: function (args, cb, soapHeader, req) {
lastReqAddress = req.connection.remoteAddress;
var validationError = {
Fault: {
Code: {
Value: "soap:Sender",
Subcode: {
value: "rpc:BadArguments"
}
},
Reason: {
Text: "Processing Error"
},
statusCode: 500
}
};
var isValidPrice = function () {
var price = args.price;
if (isNaN(price) || (price === ' ')) {
return cb(validationError);
}
price = parseInt(price, 10);
var validPrice = (price > 0 && price < Math.pow(10, 5));
return cb(null, {
valid: validPrice
});
};
setTimeout(isValidPrice, 10);
}
}
}
};
var wsdl = fs.readFileSync(__dirname + '/../wsdl/stockquote.wsdl', 'utf-8').toString();
server = express();
soapServer = soap.listen(server, '/stockquote', service, wsdl);
这里是 stockquote.wsdl:
<wsdl:definitions name="StockQuote"
targetNamespace="http://example.com/stockquote.wsdl"
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xsd:schema targetNamespace="http://example.com/stockquote.xsd" xmlns:xsd="http://www.w3.org/2000/10/XMLSchema">
<xsd:element name="TradePriceRequest">
<xsd:complexType>
<xsd:all>
<xsd:element name="tickerSymbol" type="string"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="TradePrice">
<xsd:complexType>
<xsd:all>
<xsd:element name="price" type="float"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="TradePriceSubmit">
<xsd:complexType>
<xsd:all>
<xsd:element name="tickerSymbol" type="string"/>
<xsd:element name="price" type="float"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="valid" type="boolean"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="GetLastTradePriceInput">
<wsdl:part name="body" element="xsd1:TradePriceRequest"/>
</wsdl:message>
<wsdl:message name="GetLastTradePriceOutput">
<wsdl:part name="body" element="xsd1:TradePrice"/>
</wsdl:message>
<wsdl:message name="SetTradePriceInput">
<wsdl:part name="body" element="xsd1:TradePriceSubmit"/>
</wsdl:message>
<wsdl:message name="IsValidPriceInput">
<wsdl:part name="body" element="xsd1:TradePrice"/>
</wsdl:message>
<wsdl:message name="IsValidPriceOutput">
<wsdl:part name="body" element="xsd1:valid"/>
</wsdl:message>
<wsdl:portType name="StockQuotePortType">
<wsdl:operation name="GetLastTradePrice">
<wsdl:input message="tns:GetLastTradePriceInput"/>
<wsdl:output message="tns:GetLastTradePriceOutput"/>
</wsdl:operation>
<wsdl:operation name="SetTradePrice">
<wsdl:input message="tns:SetTradePriceInput"/>
</wsdl:operation>
<wsdl:operation name="IsValidPrice">
<wsdl:input message="tns:IsValidPriceInput"/>
<wsdl:output message="tns:IsValidPriceOutput"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetLastTradePrice">
<soap:operation soapAction="http://example.com/GetLastTradePrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="SetTradePrice">
<soap:operation soapAction="http://example.com/SetTradePrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
<wsdl:operation name="IsValidPrice">
<soap:operation soapAction="http://example.com/IsValidPrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="StockQuoteService">
<wsdl:port name="StockQuotePort" binding="tns:StockQuoteSoapBinding">
<soap:address location="http://localhost:5002/stockquote"/>
</wsdl:port>
</wsdl:service>
我有 googled 非常好我只是找不到一些路径,我还搜索了 google 函数及其与 soap 的集成,因为 firebase 函数只是 google 用于 firebase
查看 node-soap
的源代码,您应该可以直接将 _requestListener
传递给 Cloud Function 的 onRequest
函数:
exports.stockquote = functions.https.onRequest(soapServer._requestListener)
您现在可以将 express
与云函数一起使用了:
server = express();
server.listen(5002, function () {
soap.listen(server, '/stockquote', service, wsdl);
});
exports.stockquote = functions.https.onRequest(server);
把路线放在firebase.json :
"rewrites": [
{
"source": "/stockquote",
"function": "stockquote"
}
]
在客户端上使用 javascript 进行测试时,不要忘记更改端点以覆盖 wsdl 中的 localhost
:
var soap = require('soap');
var url = 'https://[your-project-id].firebaseapp.com/stockquote?wsdl';
var args = {tickerSymbol: 'some symbol', price: 100.0};
var options = {
'endpoint' : 'https://[your-project-id].firebaseapp.com/stockquote'
};
soap.createClient(url, options, function(err, client) {
if (err) throw err;
//print service in json
console.log(client.describe());
client.GetLastTradePrice(args, function(err, result) {
if(err)
console.log("err = "+ err.message);
console.log(result);
res.status(200).send(result);
});
});
你走在正确的道路上,
如果您希望服务器的 GCF 路径为 http://myfunctions.domain.com/stockquote/
那么你在js文件中的最后一行应该是
soapServer = soap.listen(server, '/', service, wsdl)
之后,在您的 Google 云函数 index.js
中输入:
exports.stockquote = functions.https.onRequest(server)
您必须确保您的 SOAP 请求到达端点 并在末尾添加一个尾部斜杠 。如果您无法控制现有客户端,那么您可以添加自己的 URL 处理程序,该处理程序将查看 URL 并将 /
添加到您的 URL收到功能。
即:
exports.stockquote = functions.https.onRequest( gcfURLHandler(server) );
其中 gcfURLHandler
定义为
function gcfURLHandler( handler ){
return (req, res ) => {
if( !req.url || !req.path ) {
req.url = "/" + (req.url || '');
}
handler( req, res )
}
}
从评论 here 中了解到这一点。 (原代码中还有其他提示)
上周我正在处理这个问题,看到了未回答的问题。花了很多时间四处挖掘,终于弄明白了。希望这可以帮助其他想要做同样事情的人!
我需要使用 firebase 函数实现 soap 网络服务。 我发现一个名为 soap-node soap-module-github 的模块看起来很有前途,因为它与 express 集成,firebase 说它使用 express 进行 http 调用,但问题是我不知道如何将该模块与 firebase 集成函数,因为 firebase 函数是客户端发出的 http 调用的处理程序,任何帮助都会非常有帮助。
这是我到目前为止成功创建的代码:
var fs = require('fs'),
soap = require('soap'),
express = require('express'),
lastReqAddress;
var server = express();
service = {
StockQuoteService: {
StockQuotePort: {
GetLastTradePrice: function (args, cb, soapHeader) {
if (soapHeader)
return {
price: soapHeader.SomeToken
};
if (args.tickerSymbol === 'trigger error') {
throw new Error('triggered server error');
} else if (args.tickerSymbol === 'Async') {
return cb({
price: 19.56
});
} else if (args.tickerSymbol === 'SOAP Fault v1.2') {
throw {
Fault: {
Code: {
Value: "soap:Sender",
Subcode: {
value: "rpc:BadArguments"
}
},
Reason: {
Text: "Processing Error"
}
}
};
} else if (args.tickerSymbol === 'SOAP Fault v1.1') {
throw {
Fault: {
faultcode: "soap:Client.BadArguments",
faultstring: "Error while processing arguments"
}
};
} else {
return {
price: 19.56
};
}
},
SetTradePrice: function (args, cb, soapHeader) {},
IsValidPrice: function (args, cb, soapHeader, req) {
lastReqAddress = req.connection.remoteAddress;
var validationError = {
Fault: {
Code: {
Value: "soap:Sender",
Subcode: {
value: "rpc:BadArguments"
}
},
Reason: {
Text: "Processing Error"
},
statusCode: 500
}
};
var isValidPrice = function () {
var price = args.price;
if (isNaN(price) || (price === ' ')) {
return cb(validationError);
}
price = parseInt(price, 10);
var validPrice = (price > 0 && price < Math.pow(10, 5));
return cb(null, {
valid: validPrice
});
};
setTimeout(isValidPrice, 10);
}
}
}
};
var wsdl = fs.readFileSync(__dirname + '/../wsdl/stockquote.wsdl', 'utf-8').toString();
server = express();
soapServer = soap.listen(server, '/stockquote', service, wsdl);
这里是 stockquote.wsdl:
<wsdl:definitions name="StockQuote"
targetNamespace="http://example.com/stockquote.wsdl"
xmlns:tns="http://example.com/stockquote.wsdl"
xmlns:xsd1="http://example.com/stockquote.xsd"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xsd:schema targetNamespace="http://example.com/stockquote.xsd" xmlns:xsd="http://www.w3.org/2000/10/XMLSchema">
<xsd:element name="TradePriceRequest">
<xsd:complexType>
<xsd:all>
<xsd:element name="tickerSymbol" type="string"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="TradePrice">
<xsd:complexType>
<xsd:all>
<xsd:element name="price" type="float"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="TradePriceSubmit">
<xsd:complexType>
<xsd:all>
<xsd:element name="tickerSymbol" type="string"/>
<xsd:element name="price" type="float"/>
</xsd:all>
</xsd:complexType>
</xsd:element>
<xsd:element name="valid" type="boolean"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="GetLastTradePriceInput">
<wsdl:part name="body" element="xsd1:TradePriceRequest"/>
</wsdl:message>
<wsdl:message name="GetLastTradePriceOutput">
<wsdl:part name="body" element="xsd1:TradePrice"/>
</wsdl:message>
<wsdl:message name="SetTradePriceInput">
<wsdl:part name="body" element="xsd1:TradePriceSubmit"/>
</wsdl:message>
<wsdl:message name="IsValidPriceInput">
<wsdl:part name="body" element="xsd1:TradePrice"/>
</wsdl:message>
<wsdl:message name="IsValidPriceOutput">
<wsdl:part name="body" element="xsd1:valid"/>
</wsdl:message>
<wsdl:portType name="StockQuotePortType">
<wsdl:operation name="GetLastTradePrice">
<wsdl:input message="tns:GetLastTradePriceInput"/>
<wsdl:output message="tns:GetLastTradePriceOutput"/>
</wsdl:operation>
<wsdl:operation name="SetTradePrice">
<wsdl:input message="tns:SetTradePriceInput"/>
</wsdl:operation>
<wsdl:operation name="IsValidPrice">
<wsdl:input message="tns:IsValidPriceInput"/>
<wsdl:output message="tns:IsValidPriceOutput"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetLastTradePrice">
<soap:operation soapAction="http://example.com/GetLastTradePrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="SetTradePrice">
<soap:operation soapAction="http://example.com/SetTradePrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
<wsdl:operation name="IsValidPrice">
<soap:operation soapAction="http://example.com/IsValidPrice"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="StockQuoteService">
<wsdl:port name="StockQuotePort" binding="tns:StockQuoteSoapBinding">
<soap:address location="http://localhost:5002/stockquote"/>
</wsdl:port>
</wsdl:service>
我有 googled 非常好我只是找不到一些路径,我还搜索了 google 函数及其与 soap 的集成,因为 firebase 函数只是 google 用于 firebase
查看 node-soap
的源代码,您应该可以直接将 _requestListener
传递给 Cloud Function 的 onRequest
函数:
exports.stockquote = functions.https.onRequest(soapServer._requestListener)
您现在可以将 express
与云函数一起使用了:
server = express();
server.listen(5002, function () {
soap.listen(server, '/stockquote', service, wsdl);
});
exports.stockquote = functions.https.onRequest(server);
把路线放在firebase.json :
"rewrites": [
{
"source": "/stockquote",
"function": "stockquote"
}
]
在客户端上使用 javascript 进行测试时,不要忘记更改端点以覆盖 wsdl 中的 localhost
:
var soap = require('soap');
var url = 'https://[your-project-id].firebaseapp.com/stockquote?wsdl';
var args = {tickerSymbol: 'some symbol', price: 100.0};
var options = {
'endpoint' : 'https://[your-project-id].firebaseapp.com/stockquote'
};
soap.createClient(url, options, function(err, client) {
if (err) throw err;
//print service in json
console.log(client.describe());
client.GetLastTradePrice(args, function(err, result) {
if(err)
console.log("err = "+ err.message);
console.log(result);
res.status(200).send(result);
});
});
你走在正确的道路上,
如果您希望服务器的 GCF 路径为 http://myfunctions.domain.com/stockquote/
那么你在js文件中的最后一行应该是
soapServer = soap.listen(server, '/', service, wsdl)
之后,在您的 Google 云函数 index.js
中输入:
exports.stockquote = functions.https.onRequest(server)
您必须确保您的 SOAP 请求到达端点 并在末尾添加一个尾部斜杠 。如果您无法控制现有客户端,那么您可以添加自己的 URL 处理程序,该处理程序将查看 URL 并将 /
添加到您的 URL收到功能。
即:
exports.stockquote = functions.https.onRequest( gcfURLHandler(server) );
其中 gcfURLHandler
定义为
function gcfURLHandler( handler ){
return (req, res ) => {
if( !req.url || !req.path ) {
req.url = "/" + (req.url || '');
}
handler( req, res )
}
}
从评论 here 中了解到这一点。 (原代码中还有其他提示)
上周我正在处理这个问题,看到了未回答的问题。花了很多时间四处挖掘,终于弄明白了。希望这可以帮助其他想要做同样事情的人!