The URL that the getJSON request is sent to definitely exists, but the request fails with a 404 error. The URL just hosts a JSON object: here. I've also tried using the same request but replacing the destination with a local JSON file hosted in the same directory, which also fails with a 404 error. I'm guessing this
means that the error is either with my getJSON request, or with my node.js server configuration.
This is the function that makes the getJSON call:
function loginFunction(){
//check browser support
if(typeof(Storage) !== "undefined"){
//store dat shit
sessionStorage.setItem("username", document.getElementById('username').value);
sessionStorage.setItem("password", document.getElementById('password').value);
$(document).ready(function(){
$.getJSON(createUsernameURL(), function(data){
console.log(data);
var responseUsername = data.username;
document.getElementById("unresult").innerHTML = responseUsername;
var responsePassword = data.password;
document.getElementById("pwresult").innerHTML = responsePassword;
});
});
}else{
document.getElementById("pwresult").innerHTML = "your browser is out of date";
}
And this is the config file for my node.js server:
const http = require('http');
const express = require('express');
const app = express();
app.listen(3000,function(){
console.log(__dirname)
});
app.get('/', (req,res) => {
res.sendFile(__dirname + '/index.html');
});
app.use("/static", express.static(__dirname + '/static'));
The createUsernameURL() function just appends a couple pieces of user-entered information to a base URL, but even hard-coding the exact database link mentioned above gives the same issues.
Related
I am trying to send a csv file which is uploaded by the user, from browser to nodejs server for processing (file is over 50 mb, so the page becomes unresponsive). I'm using XMLHttpRequest for this purpose. I cannot find a solution to this. Any help is appreciated.
Javascript code
var csv = document.getElementById('inputFile').files[0];
var request = new XMLHttpRequest();
request.open("POST", "/handleFile", true);
request.setRequestHeader("Content-type", "text/csv");
request.onreadystatechange = function() {
if (request.readyState === XMLHttpRequest.DONE && request.status === 200) {
console.log("yey");
}
}
request.send(csv);
NodeJS server
var express = require('express')
var app = express()
var bodyparser = require('body-parser')
app.post('/handleFile', function(req, res) {
console.log(req.body); // getting {} empty object here....
console.log(req);
var csv = req.body;
var lines = csv.split("\n");
var result = [];
var headers = lines[0].split("\t");
for (var i = 1; i < lines.length; i++) {
var obj = {};
var currentline = lines[i].split("\t");
for (var j = 0; j < headers.length; j++) {
obj[headers[j]] = currentline[j];
}
result.push(obj);
}
fileData = result;
});
What did I do wrong? Is the XMLHttpRequest used incorrectly? or there is some other thing that i did not understand ? why is there no data in req.body even though its a post request.
Or is there any other way to send a csv/text file to nodejs server from front end.
This question is not a duplicate because, the body-parser i.e. the middleware responsible for parsing the req.body does not handle text/csv and multipart/form-data . The above link is not the correct solution.
So, after looking around, I found that the problem was not my XMLHttpRequest. The request was received by the server just fine, but the body-parser could not parse the text/csv and multipart/form-data content-type. Here is the step by step answer to this problem.
In the client/browser-end whenever you are sending a large file to the server, convert it into multipart/form-data . It is the correct way of sending a text/csv/anyfile to the server.
var csv=document.getElementById('inputFile').files[0];
var formData=new FormData();
formData.append("uploadCsv",csv);
var request = new XMLHttpRequest();
//here you can set the request header to set the content type, this can be avoided.
//The browser sets the setRequestHeader and other headers by default based on the formData that is being passed in the request.
request.setRequestHeader("Content-type", "multipart/form-data"); //----(*)
request.open("POST","/handleFile", true);
request.onreadystatechange = function (){
if(request.readyState === XMLHttpRequest.DONE && request.status === 200) {
console.log("yey");
}
}
request.send(formData);
So, this is how you'll send your http request to the nodejs server.
On Node js server: Normally for application/json or any other request type the body-parser would have worked fine. But for large data and files i.e. multipart/form-data body-parser cannot parse the req.body. Thus it will give req.body as {} (empty object).
Read about body-parser here.
So for these content-type you can use other middleware for handleling the request. Some are multer,multiparty,busboy etc. I used multer.
Here is the code snipet.
//EXPRESS
var express = require('express')
var app = express()
var config=require('./config.js');
//multer
var multer = require('multer');
var upload = multer();
app.post('/handleFile',upload.single('uploadCsv'), function(req, res, next) {
// req.file is the `uploadCsv` file
// req.body will hold the text fields, if there were any
console.log(req.file);
// the buffer here containes your file data in a byte array
var csv=req.file.buffer.toString('utf8');
});
NOTE:
This will still give you an error in nodejs server.
hint: It has something to do with the line (*). Try removing it and see what happens.
Google the rest ;)
I am trying to send data to node via a XMLhttprequest. The data looks like this (/q/zmw:95632.1.99999.json). My connection to Node is correct, however, I was getting an empty object so I set the headers to Content-Type application/json and then stringified the data. However Node gives me a Unexpected token " error. I presume it is because of the string, however, if I don't stringify the data then it errors out because of the "/" in the data. How do i properly send the data using pure Javascript. I want to stay away from axios and jquery because I want to become more proficient in vanilla javascript. I will make the final call to the api in node by assembling the url prefix and suffix.
Here is my code:
function getCityForecast(e){
//User selects option data from an early JSONP request.
var id = document.getElementById('cities');
var getValue = id.options[id.selectedIndex].value;
//Assembles the suffix for http request that I will do in Node.
var suffix = getValue + ".json";
var string = JSON.stringify(suffix);
console.log(suffix);
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:3000/", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.send(string);
}
Node.js code:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var path = require('path');
var request = require('request');
var http = require('http');
// ****************** Middle Ware *******************
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(__dirname + '/public'));
app.post('/', function(req, res){
console.log('working');
console.log(req.body);
});
app.listen(3000, function() { console.log('listening')});
I figured it out my mistake and this was my problem. I was trying to send a string instead of an object. So it wasn't proper JSON like this:
var string = JSON.stringify(suffix);
To remedy the situation I added:
var newObj = JSON.stringify({link : suffix});
This allowed my post to be successful because I was now sending an object hence the word Javascript Object Notation.
This is working for me, at the moment. The REST API I'm hitting requires a token. Yours might not, or it might be looking for some other custom header. Read the API's documentation. Note, you might need a polyfill/shim for cross browser-ness (promises). I'm doing GET, but this works for POST, too. You may need to pass an object. If you're passing credentials to get a token, don't forget window.btoa. Call it like:
httpReq('GET', device.address, path, device.token).then(function(data) {
//console.log(data);
updateInstrument(deviceId,path,data);
}, function(status) {
console.log(status);
});
function httpReq(method, host, path, token) {
if(method === "DELETE" || method === "GET"|| method === "POST" || method === "PUT" ){
var address = 'https://' + host + path;
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, address, true);
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader ("X-auth-token", token);
//xhr.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded");
xhr.onload = function() {
var status = xhr.status;
if (status == 200 || status == 201 || status == 202) {
resolve(xhr.response);
}
// this is where we catch 404s and alert what guage or resource failed to respond
else {
reject(status);
}
};
xhr.send();
});
} else {
console.log('invalid method');
}
};
I'm trying to know how jsonp work, so I wrote a demo working on nodejs, without jQuery. But, it was not working.
Bellow was my code:
views/index.jade
doctype html
html
head
title Demo of jsonp
body
#result
script.
var xhr = new XMLHttpRequest();
var url = '/getjsonp?callback=abc'
function abc (data) {
alert('aaa')
document.getElementById('result').innerHTML = data.name;
}
xhr.open('GET', url);
xhr.send();
server.js
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var app = express();
var data = { name: 'jacket', company: 'fdd' };
app.set('views', path.join(__dirname, 'views/'));
app.set('view engine', 'jade');
app.use(bodyParser.urlencoded({ extended: false }))
app.get('/', function (req, res, next) {
res.render('index');
});
app.get('/getjsonp', function (req, res, next) {
var callback = req.query.callback;
res.writeHead(200, { 'Content-Type': 'application/javascript' });
res.end(callback + '(' + JSON.stringify(data) + ')');
});
app.listen(3000);
And here is the response:
abc({"name":"jacket","company":"fdd"})
As my expect, I define a method abc() in index.jade, then request '/getjsonp?callback=abc' by async ajax, it'll response a javascript which will execute the method: abc().
But it was not working like that, I dont know anywhere was wrong, hope you can tell me if you know.
Thanks!
I believe that everything is working here, it's just that in the client, you'll need to retrieve the data sent back from the server using:
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
eval(xhr.responseText);
}
};
hope this helps :)
NOTE: eval will make a string like "abc({a: 'a'})" to running the function abc with a parameter with 1 argument (which is the object {a: 'a'}
And I found another way to make it work without ajax:
<script>
function abc (data) {
alert('aaa')
document.getElementById('result').innerHTML = data.name;
}
</script>
<script type="text/javascript" src="/getjsonp?callback=abc"></script>
Edit: I know using express or whatever would be easier, but this is all a learning exercise, so sorry if this is all massively convoluted, haha!
Edit 2: It appears (after adding a few console logs for debugging) that it seems the problem has something to do with the fact that when the browser makes one request to the server (say, for style.css), it makes another request (e.g. for login-fail.js) before completing the response for the first request. It seems these multiple requests from the browser cause some sort of problem, each subsequent request preventing the previous from completing. Yikes, I need help.
Edit 3: After some debugging, it appears that the pathname variable does not change its value upon each request. For some reason, pathname's value persists over each request and this makes every request's response the same - stranger still, the value for uri changes over each request (and the uri is what gives the pathname its value...) still trying to find out why this bizarre behaviour is happening.
So I've been having this problem when the server makes requests for external .js and .css files linked to specific .html files. The responses are always inconsistent. For instance, sometimes the code will run perfectly, other times the css will load and not the js, sometimes both, sometimes neither. I am not able to determine whether this is because my code is synchronous, or for some other reason. Here is my code:
Server.js
//Module requires
var http = require("http"),
fs = require("fs"),
path = require('path'),
url = require('url'),
invoke = require("./invoke");
//Object "MIMETYPES"
//Maps relationships between file extensions and their respective MIME Content-Types
var MIMETYPES = {
".html": "text/html",
".jpeg": "image/jpeg",
".jpg": "image/jpeg",
".png": "image/png",
".js": "text/javascript",
".css": "text/css"
};
//Object "invokeOptions"
//Options passed to Invoke() function for POST requests
var invokeOptions = {
postData : "",
uri : ""
}
var PORT = 8888;
//HTTP Server Begin
http.createServer(function(req, res) {
var uri = url.parse(req.url).pathname;
pathname = path.resolve(__dirname, "..") + uri;
console.log("Recieved " + req.method + " request for : " + uri);
invokeOptions.uri = uri;
//GET requests wrapper
if (req.method == "GET"){
//Invoke() function handler for GET requests
if (path.extname(pathname) == ""){
invoke.invoke(invokeOptions, req, res);
return;
}
//Static file server for GET requests
fs.exists(pathname, function(exists) {
if(!exists) {
console.log("Requested file \'" + pathname + "\' doesn't exist.");
res.writeHead(404, {'Content-Type': 'text/plain'});
res.write('404 Not Found\n');
res.end();
return;
}
var contentType = MIMETYPES[path.extname(pathname)];
res.writeHead(200, {"Content-Type" : contentType});
console.log("Current URI: " + uri + " has content type: " + contentType);
fs.createReadStream(pathname).pipe(res);
return;
});
}
//POST requests wrapper
if (req.method == "POST"){
var postData = "";
req.on("data", function(postPacket) {
postData += postPacket;
});
req.on("end", function() {
invokeOptions.postData = postData;
invoke.invoke(invokeOptions, req, res);
return;
});
}
}).listen(PORT);
console.log ("Server listening on port: " + PORT);
Invoke.js - This handles requests for non-files, that is requests for functions on the server
var fs = require("fs"),
querystring = require("querystring"),
path = require("path");
function invoke (options, req, res){
process.stdout.write("Invoking function --> ");
if (options.uri == "/"){
console.log("Index");
res.writeHead(200, {"Content-Type" : "text/html"});
fs.createReadStream("../index.html").pipe(res);
return;
}
if (options.uri == "/login"){
console.log("Login");
fs.readFile(path.resolve("../users.json"), "UTF-8", function(err, data){
if (err) throw err;
var json = JSON.parse(data);
var user = querystring.parse(options.postData).username,
password = querystring.parse(options.postData).password;
console.log("Submitted Username: " + user + "\nSubmitted Password: " + password);
if (json.users[0].username == user && json.users[0].password == password){
res.writeHead(200, {"Content-Type" : "text/html"});
fs.createReadStream("../app.html").pipe(res);
return;
}
else {
res.writeHead(300, {"Content-Type" : "text/html"});
fs.createReadStream("../login-fail.html").pipe(res);
return;
}
});
}
else {
console.log("Error! Bad request.");
res.writeHead(400, {"Content-Type" : "text/plain"});
res.end("Error 400: Bad Request. \nThere is no function corresponding to that request.");
}
}
exports.invoke = invoke;
Login-fail.js - This is the code that hardly ever loads
$(document).ready(function() {
var current = 3;
var countdown = $(".countdown");
function down (){
current--;
if (current != 0){
countdown.text(current);
}
else {
clearInterval(interval);
window.location.replace("./");
}
}
var interval = setInterval(down, 1000);
});
Basically, the index.html file is a form which accepts a username and password, compares the submitted POST data to a json file, and if it matches the hashes in the json file it requests app.html, otherwise it requests login-fail.html. When the login-html file is called, it has linked to it css and js which when requested hardly ever run!
Also, I thought it should be noted that the console.logs for "content-type" when requesting the css is 'text/javascript' when it doesn't work. Any help would be massively appreciated!
Holy crap.
Pathname wasn't being declared as a variable each request, because I used a ; instead of a ,
I'll go die now ladies and gents.
The relative paths you're using in your login-fail.html are probably not resolving correctly because the URL path doesn't change (/login), so the browser is looking for /login/css/style.css and /login/js/login-fail.js. Try modifying your login-fail.html to use absolute paths instead of relative paths.
I have some issues with getting json data from a json file, first of all here is the error:
"NetworkError: 404 Not Found - http://localhost:8000/channels.json"
Here is the code for getting json data in my html file:
<div id="result"></div>
<script type="text/javascript">
// read episodes in channel
function ajaxRequest(){
if (window.XMLHttpRequest) // if Mozilla, Safari etc
return new XMLHttpRequest();
else
return false;
}
var mygetrequest=new ajaxRequest();
mygetrequest.onreadystatechange=function(){
if (mygetrequest.readyState==4){
if (mygetrequest.status==200 || window.location.href.indexOf("http")==-1){
var jsondata=eval("("+mygetrequest.responseText+")"); //retrieve result as an JavaScript object
var rssentries=jsondata.channels;
var output='<ul>';
for (var i=0; i<rssentries.length; i++){
output+='<li>';
output+=rssentries[i].channel_id+'</a><br>';
output+=''+rssentries[i].name+'';
output+='</li>';
}
output+='</ul>';
document.getElementById("result").innerHTML=output;
}else{
alert("An error has occured making the request");
}
}
}
mygetrequest.open("GET", "channels.json", true);
mygetrequest.send(null);
</script>
so the html works standing alone, but when i try to render it in my node server, i get error, code in my node server in express:
var express = require('express');
var http = require('http');
var app = express();
var server = module.exports = http.createServer(app);
server.listen(8000);
console.log("Express server listening on port 8000 in %s mode");
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.get('/episodes', function(req, res){
res.render('episodes.html');
});
So i have to do the json data call in the server in order to avoid the error, there's no other way?
If u are rendering on the server, you can't use Ajax. Ajax only runs from within the browser, not on the server. On the server you have to read the file directly, pass it to the renderer, and render it inside of the template. For example:
var fs = require('fs');
app.get('/episodes', function(req, res){
fs.readFile('./public/channels.json', 'utf8', function (err, data) {
var channels = JSON.parse(data);
res.render('episodes.html', channels);
});
});
Inside your ejs template you'll have to render the channels directly into the page.
Another option to go along with what Max suggested is to use res.format() to return the specific content type you want.
http://expressjs.com/api.html#res.format
res.format({
text: function(){
res.send(...);
},
html: function(){
res.send(...);
},
json: function(){
fs.readFile('./public/channels.json', 'utf8', function (err, data) {
var channels = JSON.parse(data);
res.send(channels);
});
}
});