Submit POST form with latin1 charset in Node.js - node.js

Short version of the problem : in my Node.js app using Sails.js framework, I'd like to send data (simple UTF-8 text charset) to a distant server POST form, which has ISO-8859-15 charset.
Details : using the request package, the form is submitted this way :
var postFields = {
'message' : message, // <== this var contains chars such as é,à,ç, etc.
'submit' : 'Send'
};
var opts = {
uri: url,
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:33.0) Gecko/20100101 Firefox/33.0',
'Cookie' : cookie,
'Content-type': "application/x-www-form-urlencoded; charset=ISO-8859-15"
},
form: postFields
};
request.post(opts, function(error, response, body) {
if (!error && response.statusCode == 200) {
return callback(null, true);
} else {
return callback(null, false);
}
});
This works fine, my form is sent successfully, except the "é" chars turned into ugly "é" to the distant server. In the 'Content-type' property of the opts object, I tried to set charset to ISO-8859-15 / UTF-8 / none, text/html or application/x-www-form-urlencoded, still doesn't work...
Don't know if this helps, but here is what I have to do :
1) get data from the distant server (latin1 encoded), then convert it to UTF-8 text :
var iconv = require('iconv-lite');
request(options, function(error, response, body) {
var decodedBody = iconv.decode(body, 'iso-8859-15');
return callback(null, decodedBody)
}
});
Great, now I have beautiful accents.
2) update this data, then send it back to the distant server using the first code block above.
Actually I used to do exactly the same operations with PHP, which worked fine : instead of sending the "raw" UTF-8 text message (postFields object), it was passed into the utf8_decode() func and the distant server displayed correctly the accents.
I gave a try to js implementation of this function => the accents are correctly sent, but this time all other normal chars are turned weird...
Hoping this is clear enough, if you need more details, code, or practical examples : no problem! Thanks for reading :)

Well, after 3 years and 10 months I faced a similar problem but I managed to find a solution!
To resolve this, you need to use urlencode and body instead of form, like this:
const urlencode = require('urlencode');
const request = require('request');
const fields = {
message: 'é à ç'
};
const opts = {
uri: 'https://localhost',
headers: {
'Content-type': 'application/x-www-form-urlencoded; charset=ISO-8859-1'
},
body: urlencode.stringify(fields, {
charset: 'latin1'
})
};
request.post(opts, (err, res, body) => {
if (err) {
throw err;
}
console.log(res.statusCode);
});
This is because request encodes form fields using UTF-8 so you never get Latin-1 characters even if you encode them before (you'll end up with re-encoded characters).
I've tested this and it works as expected, so I hope this helps someone else!

Related

How to set POST encoding with request module on node.js?

I'm using request module on node.js but there is something problem with encoding option. beneath codes are simple post request, but I don't know how to set up encoding of form field data. I already set headers to 'Content-Type': 'application/x-www-form-urlencoded; charset=euc-kr' But it doesn't works. field data is korean, like "안녕하세요", and I should post it with euc-kr encoding. (The site takes euc-kr, not utf8)
The same program on Java application, I coded like this :
PrintWriter wr = new PrintWriter(new OutputStreamWriter(conn.getOutputStream(), "euc-kr"));
But I don't know how to in nodejs. Can anyone give some solution...?
Code Sample
//Load the request module
var request = require('request');
//Lets configure and request
request({
url: 'http://google.com', //URL to hit
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=euc-kr' },
method: 'POST',
form: {
field1: 'data',
field2: 'data'
}
}, function(error, response, body){
if(error) {
console.log(error);
} else {
console.log(response.statusCode, body);
}
});
Finally I got a soultion, and I solved this problem.
If you send a data as a form using request module, the module change your form encoding to utf-8 by force. So even you setted your form encoding to another charset, the module changes your charset to utf8 again. You can see that at request.js on line 1120-1130.
So, You'd better send a data by 'body' option, not 'form' option.
Node doesn't support EUC-KR so you can use iconv-lite to extend the native encodings available and set the encoding option in request.
List of Natively Supported Encodings
iconv.extendNodeEncodings(); only works for node pre v4+. See here to get this working for a newer version of node.
var iconv = require('iconv-lite');
var request = require('request');
// This will add to the native encodings available.
iconv.extendNodeEncodings();
request({
url: 'http://google.com', //URL to hit
method: 'POST',
form: {
field1: 'data',
field2: 'data'
},
encoding: 'EUC-KR'
}, function(error, response, body){
if(error) {
console.log(error);
} else {
console.log(response.statusCode, body);
}
});
iconv.undoExtendNodeEncodings();

how to send a pdf base64 variable through a nodejs request?

Trying to send a base64 pdf string with request, but I can't seem to figure out the proper structure of the request. Thanks in advance for the help!
var dpdf = pdfvar.toString('base64');
var options = {
method: 'POST',
body: dpdf,
url: FILEPICKER_URL,
headers: [
{
name: 'content-type',
value: 'application/pdf'
}
]
};
request(options, function(err, httpResponse, body){
console.log('body: ', body);
console.log('code ', httpResponse.statusCode)
});
The other side is expecting a PDF
application/pdf
and not a BASE64 representation of it.
Anyway, looking at what you are trying to do, without necessarily understanding how you are trying to do it... I would try and append a data url compatible header to your string like so :
var dpdf = 'data:application/pdf;base64,' + pdfvar.toString('base64')

How to return image in NodeJS after intercepted image get request?

I am trying to intercept requests for html elements (like images and scripts) that is referenced with relative path from my website and retrieve them from a 2nd website using requestJS for NodeJS , this works with scripts but I can’t figure a way to retrieve images.
For example in my home page .html (127.0.0.1:3030) I have:
<script src="/main/mainscript.js"></script>
Intercepted to retrieve "http://my2website.com/main/mainscript.js", works fine
<img src=”/images/logo.png”/>
Intercepted to retrieve "http://my2website.com/images/logo.png", but I always get error even if I can see that the response headers attributes matches the required file.
Using this code :
app.get('*', function (req, res) {
var options = {
url: 'http://my2website.com'+ req.path,
headers: {
'User-Agent': req.headers['user-agent']
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
res.send(body);
}
else {
console.log('request error: ' + JSON.stringify(error));
res.redirect('/');
}
});
});
Please forgive my poor English.
Set encoding: null in your options. This will keep binary data intact by keeping the response as a Buffer instance instead of converting it to a UTF-8 string:
var options = {
url: 'http://my2website.com'+ req.path,
headers: {
'User-Agent': req.headers['user-agent']
},
encoding: null
};

Images are not proxied correctly when using NodeJS + Request module

I have a proxy that works well (as far as I can tell) UNTIL I attempt to proxy images (or perhaps any binary data?). By my estimations, the below code should work, but it does not. I'm sure I"m doing something obviously dumb, but I've been digging through forums and apis and I have yet to hit upon the correct approach.
The 'core' of my proxy looks something like the following.
function(req, res) {
...
options = {
url: 'a url',
headers: {
'Authorization': auth
}
};
request(options,
function(e, r, b){
var encoding = (r.headers['content-type'].indexOf('image') === -1) ? 'utf8' : 'binary';
res.writeHead(200, {
'Content-Length': r.headers['content-length'],
'Content-Type': r.headers['content-type']
});
if (encoding === 'binary') {
b = new Buffer(b);
}
res.end(b, encoding);
});
}
What am I missing here?
Thanks in advance for any and all help!
My problem was not with the response (as I though originally), but rather the fact that the request module was encoding it's response body to unicode by default, when disabled (encoding: null), the response body is converted to a buffer which is easily consumed by the response.
options = {
url: url,
encoding: null,
headers: {
'Authorization': auth
}
};
request(options,
function(e, r, b){
var encoding = (r.headers['content-type'].indexOf('image') === -1) ? 'utf8' : 'binary';
res.end(b, encoding);
});

nodejs - first argument must be a string or Buffer - when using response.write with http.request

I'm simply trying to create a node server that outputs the HTTP status of a given URL.
When I try to flush the response with res.write, I get the error: throw new TypeError('first argument must be a string or Buffer');
But if I replace them with console.log, everything is fine (but I need to write them to the browser not the console).
The code is
var server = http.createServer(function (req, res) {
res.writeHead(200, {"Content-Type": "text/plain"});
request({
uri: 'http://www.google.com',
method: 'GET',
maxRedirects:3
}, function(error, response, body) {
if (!error) {
res.write(response.statusCode);
} else {
//response.end(error);
res.write(error);
}
});
res.end();
});
server.listen(9999);
I believe I should add a callback somewhere but pretty confused and any help is appreciated.
I get this error message and it mentions options.body
I had this originally
request.post({
url: apiServerBaseUrl + '/v1/verify',
body: {
email: req.user.email
}
});
I changed it to this:
request.post({
url: apiServerBaseUrl + '/v1/verify',
body: JSON.stringify({
email: req.user.email
})
});
and it seems to work now without the error message...seems like bug though. I think this is the more official way to do it:
request.post({
url: apiServerBaseUrl + '/v1/verify',
json: true,
body: {
email: req.user.email
}
});
response.statusCode is a number, e.g. response.statusCode === 200, not '200'. As the error message says, write expects a string or Buffer object, so you must convert it.
res.write(response.statusCode.toString());
You are also correct about your callback comment though. res.end(); should be inside the callback, just below your write calls.
Request takes a callback method, its async! So I am assuming, by the time the callback is executed the res.end() might get called. Try closing the request within the callback.
Well, obviously you are trying to send something which is not a string or buffer. :) It works with console, because console accepts anything. Simple example:
var obj = { test : "test" };
console.log( obj ); // works
res.write( obj ); // fails
One way to convert anything to string is to do that:
res.write( "" + obj );
whenever you are trying to send something. The other way is to call .toString() method:
res.write( obj.toString( ) );
Note that it still might not be what you are looking for. You should always pass strings/buffers to .write without such tricks.
As a side note: I assume that request is a asynchronous operation. If that's the case, then res.end(); will be called before any writing, i.e. any writing will fail anyway ( because the connection will be closed at that point ). Move that line into the handler:
request({
uri: 'http://www.google.com',
method: 'GET',
maxRedirects:3
}, function(error, response, body) {
if (!error) {
res.write(response.statusCode);
} else {
//response.end(error);
res.write(error);
}
res.end( );
});
if u want to write a JSON object to the response then change the header content type to application/json
response.writeHead(200, {"Content-Type": "application/json"});
var d = new Date(parseURL.query.iso);
var postData = {
"hour" : d.getHours(),
"minute" : d.getMinutes(),
"second" : d.getSeconds()
}
response.write(postData)
response.end();
And there is another possibility (not in this case) when working with ajax(XMLhttpRequest), while sending information back to the client end you should use res.send(responsetext) instead of res.end(responsetext)
Although the question is solved, sharing knowledge for clarification of the correct meaning of the error.
The error says that the parameter needed to the concerned breaking function is not in the required format i.e. string or Buffer
The solution is to change the parameter to string
breakingFunction(JSON.stringify(offendingParameter), ... other params...);
or buffer
breakingFunction(BSON.serialize(offendingParameter), ... other params...);
The first argument must be one of type string or Buffer. Received type object
at write_
I was getting like the above error while I passing body data to the request module.
I have passed another parameter that is JSON: true and its working.
var option={
url:"https://myfirstwebsite/v1/appdata",
json:true,
body:{name:'xyz',age:30},
headers://my credential
}
rp(option)
.then((res)=>{
res.send({response:res});})
.catch((error)=>{
res.send({response:error});})

Resources