I'm trying establish an AJAX connection on node 0.10.3 using mootools. My code is:
Client
var ajax = new Request({
url: '/register',
method: 'post',
onSuccess: function(responseText){
console.log(responseText);
}
})
var json = {data:'data'};
ajax.send(JSON.stringify(json));
//ajax.send(json);
Server
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.listen(1344);
app.post('/register', function(req,res){
//Auth.register()
console.log(req.body);
res.contentType('json');
res.send({ some: JSON.stringify({response:'json'}) })
})
The connection is working Ok. On the client I get the response. So the console.log(responseText) inside the OnSucces method is printing the correct value.
But on the server side, the console.log(req.body) is undefined.
I have a few doubts here. Does mootools converts the javascript object to a json string? Is it necessary to convert de object at all? What is the correct way of sending information trough AJAX to node? Is this ajax.send(JSON.stringify(json)); OK? Or is it like this ajax.send(json);?
Do I need to specify the headers to be json?
Apart for solving the particular problem, it would be nice some article, o some feedback to definitely clarify this concepts around node.js.
EDIT
I'm going to post the correct code, for those who are facing a similar problem. Noah was right about the parser, but there is another detail, the parser is expecting for the key data. Luckily I was using data as example!
Client
var ajax = new Request({
url: '/register',
method: 'post',
onSuccess: function(responseText){
console.log(responseText); //Logs "some": "{\"response\":\"json\"}"
}
})
ajax.send({data:{ok:'OK'}});
Server
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(express.bodyParser());
app.listen(1344);
app.post('/register', function(req,res){
console.log(req.body); //logs {ok:'OK'}
res.contentType('json');
res.send({ some: JSON.stringify({response:'json'}) })
})
In the code you posted you are missing the bodyParser middleware app.use(express.bodyParser().
After you add the bodyParser middleware you will be able to access req.body
var express = require('express');
var app = express();
app.use(express.bodyParser()
app.use(express.static(__dirname + '/public'));
app.use(app.router)
Related
I am working on a Vodapay mini-program and would like to know if it is possible to perform a PATCH request using my.request?
You cant perform PATCH requests using my.request.It only supports GET/POST. You can read a about it on the docs here.
You could try overriding the method using X-Method-Override header. This basically tells the server Hey, I know its a POST. But could you use Patch Instead?.
This may need some additional config on your backend. I had to use the method-override package for express.js.
Mini App:
my.request({
url: 'http://localhost:3000',
headers: {
'x-method-override': 'PATCH',
'content-type': 'application/json'
},
method: 'POST',
complete: (res) => {
console.log(res);
}
});
express.js backend :
const express = require('express')
const methodOverride = require('method-override')
const PORT = process.env.PORT || 3000;
const app = express();
app.use(express.json())
app.use(methodOverride('x-method-override'))
app.get('/', (req, res)=>{
res.send('in get')
})
app.post('/', (req, res)=>{
res.send('in post')
})
app.patch('/', (req, res)=>{
res.send('in patch')
})
app.listen(PORT);
Had this working in version 1, but the whole server config has changed. This is what I have, after adding bodyparser() to the express app as was suggested by Daniel in the comments:
const server = new ApolloServer({
typeDefs,
resolvers,
playground: {
settings: {
'editor.theme': 'light',
}
},
})
// Initialize the app
const app = express();
app.use(cors())
app.use(bodyParser.json())
server.applyMiddleware({
app
})
app.post('/calc', function(req, res){
const {body} = req;
console.log("HOWDYHOWDYHOWDY", body) // <== body is {}
res.setHeader('content-type', 'application/json')
calculate(body)
.then(result => res.send(result))
.catch(e => res.status(400).send({error: e.toString()}))
})
The request body is never making it to the app.post handler, though the handler is called. I see it going out from the browser, though. Any ideas?
Update: Daniel had the correct answer, but I had another problem in the request headers I was using. Once I fixed that, then the post handler received the body.
Apollo's middleware applies the bodyparser middleware specifically to the GraphQL endpoint -- it won't affect any other routes your server exposes. In order to correctly populate req.body, you need to add the bodyparser middleware yourself, for example:
app.use(bodyParser.json())
app.post('/calc', routeHandler)
// or...
app.post('/calc', bodyParser.json(), routeHandler)
I just ran into this as well. Fixed it by passing the following into the headers:
Content-Type: application/json
So we get a file (an image file) in the front-end like so:
//html
<input type="file" ng-change="onFileChange">
//javascript
$scope.onFileChange = function (e) {
e.preventDefault();
let file = e.target.files[0];
// I presume this is just a binary file
// I want to HTTP Post this file to a server
// without using form-data
};
What I want to know is - is there a way to POST this file to a server, without including the file as form-data? The problem is that the server I am send a HTTP POST request to, doesn't really know how to store form-data when it receives a request.
I believe this is the right way to do it, but I am not sure.
fetch('www.example.net', { // Your POST endpoint
method: 'POST',
headers: {
"Content-Type": "image/jpeg"
},
body: e.target.files[0] // the file
})
.then(
response => response.json() // if the response is a JSON object
)
You can directly attach the file to the request body. Artifactory doesn't support form uploads (and it doesn't look like they plan to)
You'll still need to proxy the request somehow to avoid CORS issues, and if you're using user credentials, you should be cautious in how you treat them. Also, you could use a library like http-proxy-middleware to avoid having to write/test/maintain the proxy logic.
<input id="file-upload" type="file" />
<script>
function upload(data) {
var file = document.getElementById('file-upload').files[0];
var xhr = new XMLHttpRequest();
xhr.open('PUT', 'https://example.com/artifactory-proxy-avoiding-cors');
xhr.send(file);
}
</script>
Our front-end could not HTTP POST directly to the JFrog/Artifactory server. So we ended up using a Node.js server as a proxy, which is not very ideal.
Front-end:
// in an AngularJS controller:
$scope.onAcqImageFileChange = function (e) {
e.preventDefault();
let file = e.target.files[0];
$scope.acqImageFile = file;
};
// in an AngularJS service
createNewAcqImage: function(options) {
let file = options.file;
return $http({
method: 'POST',
url: '/proxy/image',
data: file,
headers: {
'Content-Type': 'image/jpeg'
}
})
},
Back-end:
const express = require('express');
const router = express.Router();
router.post('/image', function (req, res, next) {
const filename = uuid.v4();
const proxy = http.request({
method: 'PUT',
hostname: 'engci-maven.nabisco.com',
path: `/artifactory/cdt-repo/folder/${filename}`,
headers: {
'Authorization': 'Basic ' + Buffer.from('cdt-deployer:foobar').toString('base64'),
}
}, function(resp){
resp.pipe(res).once('error', next);
});
req.pipe(proxy).once('error', next);
});
module.exports = router;
not that we had to use a PUT request to send an image to Artifactory, not POST, something to do with Artifactory (the engci-maven.nabisco.com server is an Artifactory server). As I recall, I got CORS issues when trying to post directly from our front-end to the other server, so we had to use our server as a proxy, which is something I'd rather avoid, but oh well for now.
Let's say I have a small piece of code:
var express = require('express');
var app = express();
app.get('/', function(req, res){
//I want to acccess 'req' and get info whether it's an AJAX call
});
app.listen(3000);
When I go inside the app.get(..) function, I want to know if the get request sent is an AJAX call. What is the field in the object 'req' that can tell me this?
The header X-Requested-With: XMLHttpRequest HTTP header is not automatically added to an AJAX request, either with fetch or with the old-fashioned use of the XMLHttpRequest object. It is often added by client libraries such as jQuery.
If the header is present, it is represented in Express by request.xhr.
If you want to add it to the request (the simplest solution to this problem) you can add it as a custom header with fetch:
fetch(url, {
headers: {
"X-Requested-With": "XMLHttpRequest"
}
});
This will now be reflected in req.xhr.
A better solution is to set the Accept header to a sensible value. If you want JSON to be returned, set Accept to application/json:
fetch(url, {
headers: {
"Accept": "application/json"
}
});
You can then test for this with req.accepts:
switch (req.accepts(['html', 'json'])) { //possible response types, in order of preference
case 'html':
// respond with HTML
break;
case 'json':
// respond with JSON
break;
default:
// if the application requested something we can't support
res.status(400).send('Bad Request');
return;
}
This is much more powerful than the req.xhr approach.
app.get('/', function(req, res){
//I want to acccess 'req' and get info whether it's an AJAX call
if(req.xhr){
//the request is ajax call
}
})
var express = require('express');
var app = express();
app.get('/', function(req, res){
var isAjax = req.xhr;
});
app.listen(3000);
I want to send the filepath of a file on my server to the client in order to play it using a media player. How can I retrieve that string on the client side in order to concatenate it in the src attribute of a <video element without using sockets?
Server snippet:
res.set('content-type', 'text/plain');
res.send('/files/download.mp4');
This is how you make a request to the server without any frameworks. "/path_to_page" is the route you set to the page that is supposed to process the request.
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path_to_page', true);
xhr.onload = function(e) {
if (this.status == 200) {
console.log(this.responseText); // output will be "/files/download.mp4"
}
};
xhr.send();
}
You might also want to send some params.
var formdata = new FormData();
formdata.append("param_name", "value");
So you might for instance want to send the filename or such.
You just need to change 2 lines from the first code snippet. One would be
xhr.open('POST', '/path_to_page', true); // set to post to send the params
xhr.send(formdata); // send the params
To get the params on the server, if you are using express, they are in req.body.param_name
Which framework are you using??
You can declare base path of your project directory in ajax and the followed by your file.
jQuery.ajax({
type: "GET",
url: "/files/download.mp4",
});
Since you are using express (on node), you could use socket.io:
Server:
var io = require('socket.io').listen(80),
fs = require('fs');
io.sockets.on('connection', function (socket) {
socket.on('download', function(req) {
fs.readFile(req.path, function (err, data) {
if (err) throw err;
socket.emit('video', { video: data });
});
});
});
Client:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
...
// request a download
socket.emit('download', { path: '/files/download.mp4' });
// receive a download
socket.on('video', function (data) {
// do sth with data.video;
});
...
</script>
Edit: didnt notice you didnt want to use sockets. Still it is a viable solution.