Node.js native file upload form - node.js

i have a question: Is there any way to create native file upload system in node.js? Without modules like multer, busboy and others. I just want save it from file form. Like:
<form action="/files" method="post">
<input type="file" name="file1">
</form>
It's possible to acces this file native in node.js? Maybe im wrong, but if this modules do it, it must be possible, right?

It is possible. An example is below.
const http = require('http');
const fs = require('fs');
const filename = "logo.jpg";
const boundary = "MyBoundary12345";
fs.readFile(filename, function (err, content) {
if (err) {
console.log(err);
return
}
let data = "";
data += "--" + boundary + "\r\n";
data += "Content-Disposition: form-data; name=\"file1\"; filename=\"" + filename + "\"\r\nContent-Type: image/jpeg\r\n";
data += "Content-Type:application/octet-stream\r\n\r\n";
const payload = Buffer.concat([
Buffer.from(data, "utf8"),
Buffer.from(content, 'binary'),
Buffer.from("\r\n--" + boundary + "--\r\n", "utf8"),
]);
const options = {
host: "localhost",
port: 8080,
path: "/upload",
method: 'POST',
headers: {
"Content-Type": "multipart/form-data; boundary=" + boundary,
},
}
const chunks = [];
const req = http.request(options, response => {
response.on('data', (chunk) => chunks.push(chunk));
response.on('end', () => console.log(Buffer.concat(chunks).toString()));
});
req.write(payload)
req.end()
})
The question is interesting. I wonder why it is not already answered (4 years, 9 months).

Related

Save Response as variable and send it as Header - NodeJS

I'm currently working on sending a GET request to my own private Domain, alongside
various Headers that would be populated with various values such as 'Token' etc. - that are base64 encoded. This is running perfectly fine.
My main goal here is to send the Response of another request i'm sending to a different endpoint.
This is the modified code (I've removed various fields so please ignore any best practices for now).
const fs = require('fs');
const http = require('http');
const net = require('net');
const os = require("os");
const dns = require("dns");
const https = require("https");
var token = process.env.HOME+'/token.txt';
let base64data1 = '';
try {
if (fs.existsSync(token)) {
var data1 = fs.readFileSync(token,'utf8');
let buff1 = Buffer.from(data1);
base64data1 = buff1.toString('base64');
}} catch(error) {
console.log('')
}
var options = {
hostname: "myprivatedomain.com",
port: 443,
path: "/",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Token": base64data1
},
};
var req = https.request(options, (res) => {
res.on("data", (d) => {
process.stdout.write(d);
});
});
req.on("error", (e) => {
// console.error(e);
});
req.write(postData);
req.end();
My goal, as mentioned, is to add additional Header (In addition to the "Token" header) to my private domain, which will be populated by the Response for the following domain - www.seconddomain.com
I was thinking about creating a simple function that would retrieve the response, save it as variable and use it as my 2nd Header. Something similar to this -
function 2ndresponse(url) {
let data = '';
http.get(url, (resp) => {resp.on('data', (chunk) => {
data += chunk;
});
});
let responsevalue = Buffer.from(data);
base64data = responsevalue.toString('base64');
return http.get(url).then((resp) => resp.json());
}
var = 2ndresponse("http://www.seconddomain.com");
Hopefully this is clear enough (:
Update
I figured it out -
The workaround is to set both request in one function like so -
function req2() {
http.get({
hostname: 'seconddomain.com',
port: 80,
path: '/blahblah',
agent: false}, (res) => {
res.setEncoding('utf8');
let data = '';
res.on("data", (d) => {
var x;
x = d;
let buff5 = Buffer.from(x);
seconddomainvalue = buff5.toString('base64');
var options = {
hostname: "myprivatedomain.com",
port: 443,
path: "/",
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": postData.length,
"token": tokenvalue,
"seconddomain": seconddomainvalue
},
};
var req = https.request(options, (res) => {
res.on("data", (d) => {
process.stdout.write(d);
});
});
req.on("error", (e) => {
// console.error(e);
});
req.write(postData);
req.end();
});
});
}
req2();
Thanks
The same can be achieved using the HTTP REQUEST also, But AXIOS allows us to make HTTP requests from both the browser and Node. js applications. It allows us to make both GET and POST requests which are the most used HTTP methods.
const axios = require('axios'); // Axios import
const controllerFunction = async () => {
const firstResponse = await axios.get('https://seconddomain.com'); // Here the request will wait, as it is synchronous
const bufferValue = Buffer.from(firstResponse.data);
const base64data = bufferValue.toString('base64');
const secondResponse = await axios.post('https://myprivatedomain.com', {"body": data}, {
headers: {
"Content-Type": "application/json",
"Token": base64data
}
}); // Here the second request can use the first request response data, as this code is executed synchronously
};
Also adding the AXIOS documentation link: https://www.npmjs.com/package/axios

How to send back the data got from response.on('end') to the client-side

I'm new to NodeJs and I'm having the problem with response.on('end') I still can't find out the method to send the data I got from the response to the client side.
exports.getCheckoutSession = catchAsync(async (req, res, next) => {
const uuidv1 = require('uuid/v1');
const https = require('https');
const tour = await Tour.findById(req.params.tourId);
console.log(tour);
//parameters send to MoMo get get payUrl
var endpoint = 'https://test-payment.momo.vn/gw_payment/transactionProcessor';
var hostname = 'https://test-payment.momo.vn';
var path = '/gw_payment/transactionProcessor';
var partnerCode = 'MOMO';
var accessKey = 'accessKey';
var serectkey = 'secretKey';
var orderInfo = 'pay with MoMo';
var returnUrl = 'https://momo.vn/return';
var notifyurl = 'https://callback.url/notify';
var amount = (tour.price * 23000).toString();
console.log(amount);
var orderId = req.params.tourId;
var requestId = req.params.tourId;
var requestType = 'captureMoMoWallet';
var extraData = 'merchantName=;merchantId='; //pass empty value if your merchant does not have stores else merchantName=[storeName]; merchantId=[storeId] to identify a transaction map with a physical store
//before sign HMAC SHA256 with format
//partnerCode=$partnerCode&accessKey=$accessKey&requestId=$requestId&amount=$amount&orderId=$oderId&orderInfo=$orderInfo&returnUrl=$returnUrl&notifyUrl=$notifyUrl&extraData=$extraData
var rawSignature =
'partnerCode=' +
partnerCode +
'&accessKey=' +
accessKey +
'&requestId=' +
requestId +
'&amount=' +
amount +
'&orderId=' +
orderId +
'&orderInfo=' +
orderInfo +
'&returnUrl=' +
returnUrl +
'&notifyUrl=' +
notifyurl +
'&extraData=' +
extraData;
//puts raw signature
console.log('--------------------RAW SIGNATURE----------------');
console.log(rawSignature);
//signature
const crypto = require('crypto');
var signature = crypto
.createHmac('sha256', serectkey)
.update(rawSignature)
.digest('hex');
console.log('--------------------SIGNATURE----------------');
console.log(signature);
//json object send to MoMo endpoint
var body = JSON.stringify({
partnerCode: partnerCode,
accessKey: accessKey,
requestId: requestId,
amount: amount,
orderId: orderId,
orderInfo: orderInfo,
returnUrl: returnUrl,
notifyUrl: notifyurl,
extraData: extraData,
requestType: requestType,
signature: signature
});
//Create the HTTPS objects
var options = {
hostname: 'test-payment.momo.vn',
port: 443,
path: '/gw_payment/transactionProcessor',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body)
}
};
//Send the request and get the response
console.log('Sending....');
var req = https.request(options, res => {
console.log(`Status: ${res.statusCode}`);
console.log(`Headers: ${JSON.stringify(res.headers)}`);
console.log('Type of body', JSON.stringify(res.body));
res.setEncoding('utf8');
let fullBody = '';
res.on('data', body => {
fullBody += body;
console.log(' Real Body');
console.log(fullBody);
//console.log('Type of body', body.payUrl);
// console.log(JSON.parse(body).payUrl);
// res.redirect(JSON.parse(body).payUrl);
});
res.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
console.log('payUrl', payURL);
console.log('No more data in response.');
});
});
req.on('error', e => {
console.log(`problem with request: ${e.message}`);
});
// write data to request body
req.write(body);
req.end();
});
This is the url I got from response
payUrl https://test-payment.momo.vn/gw_payment/payment/qr?partnerCode=MOMO&accessKey=F8BBA842ECF85&requestId=5f38cc86954a6206211e2842&amount=23000&orderId=5f38cc86954a6206211e2842&signature=37ae247d56efd9ed6630b7d7d1435b88ffb8895956da5711a62ebbab8118aa7b&requestType=captureMoMoWallet
Can you please tell how could i send the data from res.on('end'), the "payURL" in the picture above, to client-side. I have tried some methods like res.writeHead, res.send, res.json( ) .... But they all returned error: res.send, res.writeHead, res.json... is not a function
This is my client-side, . If you guys don't mind , please also show me how to automatically redirect the payURL site above when the client click my button. Should I keep using window.location.replace like above ?
export const bookTour = async tourId => {
try {
const res = await fetch(
`http://localhost:3000/api/v1/bookings/checkout-session/${tourId}`,
{
method: 'POST',
body: 'a=1'
}
).then(res => window.location.replace(res.redirectURL));
console.log('The res', res);
} catch (err) {
showAlert('error', err);
}
};
This is my index.js
if (bookBtn) {
bookBtn.addEventListener('click', e => {
e.target.textContent = 'Processing...';
const tourId = e.target.dataset.tourId;
bookTour(tourId);
});
}
You're shadowing the req/res-variables from your getCheckoutSession-handler by using the same names for your http-request. If you change it to:
const request = https.request(options, response => {
// ...
let fullBody = '';
response.on('data', body => {
fullBody += body;
});
response.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
// access the handler "res" object here
res.send(payURL);
// alternatively use res.json({payURL}) to send a json response
});
});
it should work fine.
Note: Nowadays you should definitely use const/let instead of var (see this for more information)
Simple,
res.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
res.json({
payURL: payURL
})
});
or other way
res.on('end', () => {
const payURL = JSON.parse(fullBody).payUrl;
res.status(200).send({
payURL: payURL
});
});

How to call a function in different nodejs files [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
i need to call function sendPostData(postData) into fb.js because when i run post.js file i get error name call postData is not defined , postData i defined in fb.js i need to get the postData in the post.js if you check in below post.js i have coded req.write(postData);
how can i call the function ?
file name - fb.js
var https=require('follow-redirects').https;
require('./post');
var args = process.argv.slice(2);
console.log('url:' + args[0]);
var host =args[0].match (/w.*m/)[0];
console.log('host: ' + host);
var path =args[0].match (/(\/d.*)/)[0];
console.log('path: ' + path);
var opti = {
host: host,
port: 443,
path: path,
headers: {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:25.0) Gecko/20100101 Firefox/26.0'}
}
var req=https.request(opti, function (res){
//console.log('Status: ' + res.statusCode);
var data='';
res.on('data',function(chunk){
data += chunk
});
res.on('end',function(){
//console.log('Data: ' + data);
// console.log(data);
var match=data.match(/Directory Results for(.*)\/li>/);
if (!match) {
//console.log('Match not found');
match=data.match(/selected"(.*?)fbD/);
//console.log('Match: ' + match[0]);
}
var postData = '';
var match1=match.toString().match(/<a>|\/directory\/people\/(.*?)">(.*?)<\/a>/g);
match1=match1.removeDuplicates();
for (var index = 0; index < match1.length; index++) {
var link = match1[index];
link = link.substring(link.indexOf('"'),0);
link = 'http://www.facebook.com' + link;
postData += '&url=' + encodeURIComponent(link);
console.log(link);
//sendPostData(postData)=postData;
}
});
});
Array.prototype.removeDuplicates = function (){
var temp=new Array();
this.sort();
for(i=0;i<this.length;i++){
if(this[i]==this[i+1]) {continue}
else{
temp[temp.length]=this[i];
}
}
return temp;
}
req.end();
file name - post.js
var querystring = require('querystring');
var http = require('http');
function sendPostData(postData) {
var options = {
host: 'staging.360social.me',
port: 80,
path: '/queueNewDirectoryPageUrls',
method: 'POST'
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
req.write(postData);
req.end();
}
First, in your post.js
exports.sendPostData=sendPostData;
in your fb.js:
var p = require('./post');
and then call it
p.sendPostData(postData);

Node.js file download gets truncated by "require" statement

I'm trying to download and require a .js file using a node.js script, but only part of the file is being downloaded.
Specifically, this is the part that seems to be causing the problem:
response.on('data', function (chunk) {
out.write(chunk);
var theModule = require(__dirname + "/" + filename);
//less than half of the file is downloaded when the above line is included.
});
Here is the full source code:
var http = require('http');
var fs = require('fs');
downloadModule("functionChecker.js");
function downloadModule(filename) {
var google = http.createClient(80, 'www.google.com');
var request = google.request('GET', '/svn/' + filename, {
'host': 'javascript-modules.googlecode.com'
});
request.end();
out = fs.createWriteStream(filename);
request.on('response', function (response) {
response.setEncoding('utf8');
response.on('data', function (chunk) {
out.write(chunk);
var theModule = require(__dirname + "/" + filename);
//less than half of the file is downloaded when the above line is included.
//If the import statement is omitted, then the file is downloaded normally.
});
});
}
The data event can be called multiple times. You need to wait until all of the data is written.
response.setEncoding('utf8');
response.on('data', function (chunk) {
out.write(chunk);
});
response.on('end', function(){
out.end();
var theModule = require(__dirname + "/" + filename);
});
Also, createClient is deprecated, as mentioned in the docs. I'd also recommend using pipe to simplify your logic.
function downloadModule(filename) {
http.get({
hostname: 'javascript-modules.googlecode.com',
path: '/svn/' + filename
}, function(res){
var out = fs.createWriteStream(filename);
out.on('close', function(){
var theModule = require(__dirname + "/" + filename);
});
res.pipe(out);
});
}

Node.js YouTube API Upload unable to convert video

I'm trying to upload video to youtube programatically. I chose to use Node.js for the task.
I get an XML response as well as an HTTP Status Code of 201 and I see the video appear in video manager, however the video always has the message "Failed (unable to convert video file)".
I can upload the file through YouTube's own uploader on their page and there are no problems. I only have to upload to a single account, so I set up the OAuth2 for the account and stored the refresh token. The refresh token is hard-coded, though I replace it with a variable below.
Does the refresh token need to, itself, be refreshed?
My code:
var qs = require('querystring'),
https = require('https'),
fs = require('fs');
var p_data = qs.stringify({
client_id: myClientID,
client_secret: myClientSecret,
refresh_token: refreshTokenForAccount,
grant_type: 'refresh_token'
});
var p_options = {
host: 'accounts.google.com',
port: '443',
method: 'POST',
path: '/o/oauth2/token',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': p_data.length,
'X-GData-Key': myDeveloperKey
}
};
var file_path = process.argv[1] || "video.mp4";
var json = "";
var p_req = https.request(p_options, function(resp){
resp.setEncoding( 'utf8' );
resp.on('data', function( chunk ){
json += chunk;
});
resp.on("end", function(){
debugger;
var access_token = JSON.parse(json).access_token;
var title="test upload1",
description="Second attempt at an API video upload",
keywords="",
category="Comedy";
var file_reader = fs.createReadStream(file_path, {encoding: 'binary'});
var file_contents = '';
file_reader.on('data', function(data)
{
file_contents += data;
});
file_reader.on('end', function()
{
var xml =
'<?xml version="1.0"?>' +
'<entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007">' +
' <media:group>' +
' <media:title type="plain">' + title + '</media:title>' +
' <media:description type="plain">' + description + '</media:description>' +
' <media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">' + category + '</media:category>' +
' <media:keywords>' + keywords + '</media:keywords>' +
' </media:group>' +
'</entry>';
var boundary = Math.random();
var post_data = [];
var part = '';
part = "--" + boundary + "\r\nContent-Type: application/atom+xml; charset=UTF-8\r\n\r\n" + xml + "\r\n";
post_data.push(new Buffer(part, "utf8"));
part = "--" + boundary + "\r\nContent-Type: video/mp4\r\nContent-Transfer-Encoding: binary\r\n\r\n";
post_data.push(new Buffer(part, 'utf8'));
post_data.push(new Buffer(file_contents, 'binary'));
post_data.push(new Buffer("\r\n--" + boundary + "--\r\n\r\n", 'utf8'));
var post_length = 0;
for(var i = 0; i < post_data.length; i++)
{
post_length += post_data[i].length;
}
var options = {
host: 'uploads.gdata.youtube.com',
port: 443,
path: '/feeds/api/users/default/uploads',
method: 'POST',
headers: {
'Authorization': 'Bearer ' + access_token,
'X-GData-Key': myDeveloperKey,
'Slug': 'video.mp4',
'Content-Type': 'multipart/related; boundary="' + boundary + '"',
'Content-Length': post_length,
'Connection': 'close'
}
}
var req = https.request(options, function(res)
{
res.setEncoding('utf8');
console.dir(res.statusCode);
console.dir(res.headers);
var response = '';
res.on('data', function(chunk)
{
response += chunk;
});
res.on('end', function()
{
console.log( "We got response: " );
console.log(response);
});
});
for (var i = 0; i < post_data.length; i++)
{
req.write(post_data[i]);
}
req.on('error', function(e) {
console.error(e);
});
req.end();
});
});
});
p_req.write(p_data);
p_req.end();
The problem was in the file being uploaded.
This line: var file_path = process.argv[1] || "video.mp4"; should have been var file_path = process.argv[2] || "video.mp4";
Note argv[1] is the absolute path to the script being run, argv[2] is the first command line argument passed to the script.
Of course YouTube would fail to convert the "video", it wasn't video at all it was the script being run.

Resources