I am currently developing a NodeJS project with strong-soap library to receive and transmit SOAP requests and responses. Before asking question, i want to present code sample to ask my question efficiently.
server.js
//Address of this project is http://localhost:8080
const soap = require('strong-soap');
const http = require('http');
const fs = require('fs');
let myService = { //My SOAP server's service (group of methods)
Method:
function(data) //My question literally and directly related with data
{
//... Function content.
}
};
let xmlFile = fs.readFileSync('sample.wsdl');
let path = '/wsdl';
http.createServer(function (req, res) {
let soapServer = soap.listen(server, '/wsdl', myService, xmlFile);
}).listen(8080);
Assume that i have a server with codebase which is is seen above. And assume that have another Node.js project (or another .js file) which send request and transmit response from this server.
client.js
const soap = require('strong-soap');
soap.createClient('http://localhost:8080/wsdl', {forceSoap12Headers: true}, function(error, client){
if(error)
{
reject(error);
//res.sendStatus(404);
//console.log(error);
}
else{
client.Method(requestArgs, function(err, result, envelope) {
//I want to be able to sent an XML data as requestArgs
// Result in SOAP envelope body which is the wrapper element.
// In this case, result object corresponds to GetCityForecastByZIPResponse.
console.log(JSON.stringify(result));
}, null, customRequestHeader);
}
});
My question is: how i can send an XML in client.js? Or how i can receive requests in XML format without any problem in server.js? Most probably, i will deal with raw XML requests, and i want to deal with both XML and JSON requests? Help me developers!
Related
I am using strong-soap node module i want to make call to webservice, I have wsdl file.
var soap = require('strong-soap').soap;
var WSDL = soap.WSDL;
var path = require('path');
var options = {};
WSDL.open('./wsdls/RateService_v22.wsdl',options,
function(err, wsdl) {
// You should be able to get to any information of this WSDL from this object. Traverse
// the WSDL tree to get bindings, operations, services, portTypes, messages,
// parts, and XSD elements/Attributes.
var service = wsdl.definitions.services['RateService'];
//console.log(service.Definitions.call());
//how to Call rateService ??
});
I'm not sure about how strong-soap works.
But, I have some implementations of SOAP using node-soap.
Basically, the node-soap package uses Promises to keep the requests concurrent.
var soap = require('soap');
var url = 'http://www.webservicex.net/whois.asmx?WSDL';
var args = {name: 'value'};
soap.createClient(url, function(err, client) {
client.GetWhoIS(args, function(err, result) {
console.log(result);
});
});
Lets use the following sample SOAP service:
Get domain name registration record by Host Name / Domain Name (WhoIS)
To judge from your code you'd like to use a .wsdl file available locally, so saving it:
mkdir wsdl && curl 'http://www.webservicex.net/whois.asmx?WSDL' > wsdl/whois.wsdl
Now lets use the following code to query it:
'use strict';
var soap = require('strong-soap').soap;
var url = './wsdl/whois.wsdl';
var requestArgs = {
HostName: 'webservicex.net'
};
var options = {};
soap.createClient(url, options, function(err, client) {
var method = client['GetWhoIS'];
method(requestArgs, function(err, result, envelope, soapHeader) {
//response envelope
console.log('Response Envelope: \n' + envelope);
//'result' is the response body
console.log('Result: \n' + JSON.stringify(result));
});
});
It would produce some meaningful results.
WSDL.open you're trying to use is meant for working with WSDL structure
Loads WSDL into a tree form. Traverse through WSDL tree to get to
bindings, services, ports, operations, and so on.
You don't necessarily need it to call a service
I created a soap server in nodejs using the node-soap module. But I get an error indicating there is some problem in the incoming soap xml (listed below).
< soap log: { Fault: < { faultcode: 500, < faultstring:
'Invalid XML', < detail: 'Error: Non-whitespace before first
tag.\nLine: 1\nColumn: 1\nChar: -', < statusCode: undefined } }
When I searched around in google, it indicated that it is the problem of BOM (Byte Order Mark) which the windows OS inserts into the unicode buffer. Most of the solutions suggested to replace/remove this BOM before calling the xml parser.
Now, when I am using node-soap module, I am unable to figure out where to apply this fix, below being my server code.
/**
* Simple demonstration of soap service
**/
var soapService = require("./rv.js");
var xml = require('fs').readFileSync('./mmsxmlpushservicews.wsdl.xml', 'utf8');
var express = require('express');
var bodyParser = require('body-parser');
var soap = require('soap');
var app = express();
app.use(bodyParser.raw({type: function() { return true; }, limit: '5mb' }));
app.listen(8001, function(err) {
if (err) {
console.error("error:", err);
process.exit(1);
}
var server = soap.listen(app, '/smshttp/soapws', soapService, xml);
server.log = function(type, data) {
//console.log("soap log:", data);
}
console.log("service running on port 8001...");
});
In the above soap server code, is there an event / callback hook that I can make use of to modify the soap request buffer, before the soap server performs its parsing?
If yes, where and how should I be doing it?
Add this to your code after this line 'app.use(bodyParser.raw({type: function() { return true; }, limit: '5mb' }));'
app.use(function(req, res, next) {
var body = req.body.toString();
var body = body.replace('\ufeff', '');
req.body = Buffer.from(body);
next();
});
This hook in express allows you process every request, evaluate which urls have been called and safely forward to the next listener with 'next()'.
But consider that this function will be called for EVERY request, so don't forget to filter only those, where you do need to clean the string.
Is there a way to view the complete raw HTTP request and response to make debugging easier?
Here is the node module ( https://www.npmjs.com/package/node-rest-client ) and an example.
var Client = require('node-rest-client').Client;
client = new Client();
args = {
path:{"p1":"1234", "p2":"abcd"}
headers:{"Authorization":"01234567890"}
}
client.get("http://example.com/${p1}/${p2}", args, function(data, response){
// parsed response body as js object
console.log(data);
// raw response
console.log(response);
}).on('error',function(err){
console.log('something went wrong on the request', err.request.options);
});
according to source code, the Client.get() function returns a regular ol' request object created (eventually, under the hood) by node's http or https module. So try examining the return value of client.get() and seeing what's inside.
I'm trying to use streams to send data to the browser with Hapi, but can't figure our how. Specifically I am using the request module. According to the docs the reply object accepts a stream so I have tried:
reply(request.get('https://google.com'));
The throws an error. In the docs it says the stream object must be compatible with streams2, so then I tried:
reply(streams2(request.get('https://google.com')));
Now that does not throw a server side error, but in the browser the request never loads (using chrome).
I then tried this:
var stream = request.get('https://google.com');
stream.on('data', data => console.log(data));
reply(streams2(stream));
And in the console data was outputted, so I know the stream is not the issue, but rather Hapi. How can I get streaming in Hapi to work?
Try using Readable.wrap:
var Readable = require('stream').Readable;
...
function (request, reply) {
var s = Request('http://www.google.com');
reply(new Readable().wrap(s));
}
Tested using Node 0.10.x and hapi 8.x.x. In my code example Request is the node-request module and request is the incoming hapi request object.
UPDATE
Another possible solution would be to listen for the 'response' event from Request and then reply with the http.IncomingMessage which is a proper read stream.
function (request, reply) {
Request('http://www.google.com')
.on('response', function (response) {
reply(response);
});
}
This requires fewer steps and also allows the developer to attach user defined properties to the stream before transmission. This can be useful in setting status codes other than 200.
2020
I found it !! the problem was the gzip compression
to disable it just for event-stream you need provide the next config to Happi server
const server = Hapi.server({
port: 3000,
...
mime:{
override:{
'text/event-stream':{
compressible: false
}
}
}
});
in the handler I use axios because it support the new stream 2 protocol
async function handler(req, h) {
const response = await axios({
url: `http://some/url`,
headers: req.headers,
responseType: 'stream'
});
return response.data.on('data',function (chunk) {
console.log(chunk.toString());
})
/* Another option with h2o2, not fully checked */
// return h.proxy({
// passThrough:true,
// localStatePassThrough:true,
// uri:`http://some/url`
// });
};
I'm using Node.js and connect to create a simple web server. I have something similar to the following code and I can't figure out how to access the actual request message body from the request object. I'm new to this so bear with me. I'm also taking out some of the stuff that's not necessary for the example.
function startServer(dir) {
var port = 8888,
svr = connect().use(connect.static(dir, {"maxAge" : 86400000}))
.use(connect.directory(dir))
/*
* Here, I call a custom function for when
* connect.static can't find the file.
*/
.use(custom);
http.createServer(svr).listen(port);
}
function custom(req, res) {
var message = /* the message body in the req object */;
// Do some stuff with message...
}
startServer('dirName');
Make sense? I've tried logging that object to the console and it is full of TONS of stuff. I can easily see headers in there plus the request URL and method. I just can't seem to isolate the actual message body.
You should include the connect.bodyParser middleware as well:
svr = connect().use(connect.static(dir, {"maxAge" : 86400000}))
.use(connect.directory(dir))
.use(connect.bodyParser())
.use(custom);
That will provide the parsed message body as req.body to your handler.
If you want the raw message body, you shouldn't use it but instead read the req stream yourself:
function custom(req, res) {
var chunks = [];
req.on('data', function(chunk) {
chunks.push(chunk);
});
req.on('end', function() {
var rawbody = Buffer.concat(chunks);
...do stuff...
// end the request properly
res.end();
});
}
if(req.method == "POST"){
var body = '';
req.on('data', function(data){
body += data;
});
}
Then body should contain your message if you posted correctly.
A better idea would be to use Express, then use the bodyparser middleware - which will give you this functionality out of the box without worrying about somebody hammering your server. The code above has NO functionality to worry about attacks - but it will get you started.