I want to send plain html instead of a json response for one of my routes in restify. I tried setting the contentType and header property of the response but it doesn't seem to set the contentType in the header (the browser tries to download the file rather than render it).
res.contentType = 'text/html';
res.header('Content-Type','text/html');
return res.send('<html><body>hello</body></html>');
Quick way to manipulate headers without changing formatters for the whole server:
A restify response object has all the "raw" methods of a node ServerResponse on it as well.
var body = '<html><body>hello</body></html>';
res.writeHead(200, {
'Content-Length': Buffer.byteLength(body),
'Content-Type': 'text/html'
});
res.write(body);
res.end();
If you've overwritten the formatters in the restify configuration, you'll have to make sure you have a formatter for text/html. So, this is an example of a configuration that will send json and jsonp-style or html depending on the contentType specified on the response object (res):
var server = restify.createServer({
formatters: {
'application/json': function(req, res, body){
if(req.params.callback){
var callbackFunctionName = req.params.callback.replace(/[^A-Za-z0-9_\.]/g, '');
return callbackFunctionName + "(" + JSON.stringify(body) + ");";
} else {
return JSON.stringify(body);
}
},
'text/html': function(req, res, body){
return body;
}
}
});
Another option is to call
res.end('<html><body>hello</body></html>');
Instead of
res.send('<html><body>hello</body></html>');
It seems like the behaviour #dlawrence describes in his answer has changed since when the answer was posted. The way it works now (at least in Restify 4.x) is:
const app = restify.createServer(
{
formatters: {
'text/html': function (req, res, body, cb) {
cb(null, body)
}
}
})
Related
I am using React + NodeJS & Axios but have been trying to send a post request but experiencing difficulties.
The request seems to be posting successfully, but all actions at the nodejs server is returning in the "undefined" data value, even if the data is passed successfully shown in the console.
REACT
const fireAction = (data1, data2) => {
const data = JSON.stringify({data1, data2})
const url = `http://localhost:5000/data/corr/fire`;
const config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'AUTHCODE',
}
}
axios.post(url, data, config)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
fireAction("Oklahoma", "Small apartment")
NODE
app.post('/data/corr/fire', async (req, res) => {
try {
const data = req.body.data1;
console.log(data)
} catch(e) {
res.send({success: "none", error: e.message})
}
});
Result of node: "undefined"
I have added the following body parser:
app.use(express.json());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
I am not sure why this error is happening. I see there is similar questions to mine: however none of them are applicable as I'm using both express and body parser which is already suggested.
You're POSTing JSON with a content-type meant for forms. There's no need to manually set content-type if you're sending JSON, but if you want to manually override it, you can use 'Content-Type': 'application/json', and access the response in your route with req.body. If it does need to be formencoded, you'll need to build the form:
const params = new URLSearchParams();
params.append('data1', data1);
params.append('data2', data2);
axios.post(url, params, config);
Is there a way to keep the original text of the request.body after it is passed through and parsed by request.urlecoded?
request.body at any handler after this middleware (app.use(express.urlencoded())) is an object and I can't find any way to get the original raw body that was POSTed to the server.
The server can consume an incoming request only once, because the request body is streamed by the client and the HTTP protocol does not allow the server to request a "rewind" from the client. The express.urlencoded middleware parses the request into an object and express.text parses it into a string. In order to execute both in parallel, you need a "duplexer" that pipes the incoming stream into two streams, one for each middleware to parse.
app.use(function(req, res, next) {
var url = new stream.PassThrough();
url.headers = {
"content-length": req.get("content-length"),
"content-type": req.get("content-type")
};
var text = new stream.PassThrough();
text.headers = {
"content-length": req.get("content-length"),
"content-type": "text/plain"
};
req.pipe(new stream.Writable({
write(chunk, encoding, callback) {
url.push(chunk);
text.push(chunk);
callback();
},
destroy(err, callback) {
url.destroy(err);
text.destroy(err);
callback();
},
final(callback) {
url.push(null);
text.push(null);
callback();
}
}));
Promise.all([
new Promise(function(resolve, reject) {
express.urlencoded({extended: false})(url, res, function() {
resolve(url.body);
});
}),
new Promise(function(resolve, reject) {
express.text()(text, res, function() {
resolve(text.body);
});
})
]).then(function([urlBody, textBody]) {
req.urlBody = urlBody; // parsed into an object
req.textBody = textBody; // parsed as the original string
next();
});
});
Addendum
After reading the express.urlencoded documentation, I found a simpler solution:
app.use(express.urlencoded({extended: false,
verify: function(req, res, buf, encoding) {
req.textBody = buf.toString(encoding);
}
}));
This makes req.body an object (as usual) and additionally writes the original into req.textBody. But I hope my first attempt is still instructive.
I want to use a Node/Express server to stream a file to the client as an attachment. I would like to make an async request from the client to a /download endpoint and then serve an object received via API proxy to the client as a downloadable file (similar to the way res.attachment(filename); res.send(body); behaves).
For example:
fetch(new Request('/download'))
.then(() => console.log('download complete'))
app.get('/download', (req, res, next) => {
// Request to external API
request(config, (error, response, body) => {
const jsonToSend = JSON.parse(body);
res.download(jsonToSend, 'filename.json');
})
});
This will not work because res.download() only accepts a path to a file. I want to send the response from an object in memory. How is this possible with existing Node/Express APIs?
Setting the appropriate headers does not trigger a download, either:
res.setHeader('Content-disposition', 'attachment; filename=filename.json');
res.setHeader('Content-type', 'application/json');
res.send({some: 'json'});
This worked for me.
I use the content type octet-stream to force the download.
Tested on chrome the json was downloaded as 'data.json'
You can't make the download with ajax according to: Handle file download from ajax post
You can use a href / window.location / location.assign. This browser is going to detect the mime type application/octet-stream and won't change the actual page only trigger the download so you can wrap it a ajax success call.
//client
const endpoint = '/download';
fetch(endpoint, {
method: 'POST',
credentials: 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then(res => {
//look like the json is good to download
location.assign(endpoint);
})
.catch(e => {
//json is invalid and other e
});
//server
const http = require('http');
http.createServer(function (req, res) {
const json = JSON.stringify({
test: 'test'
});
const buf = Buffer.from(json);
res.writeHead(200, {
'Content-Type': 'application/octet-stream',
'Content-disposition': 'attachment; filename=data.json'
});
res.write(buf);
res.end();
}).listen(8888);
You can set the header to force the download, then use res.send
see those links
Force file download with php using header()
http://expressjs.com/en/api.html#res.set
I have this basic server:
var http = require("http");
var url = require("url");
var routing = require("./RoutingPath");
function start() {
function onRequest(request, response) {
var path = url.parse(request.url).pathname;
var query = url.parse(request.url,true).query;
routing.Route(path.toLowerCase(), query, function(recordset){
response.writeHead(200, {"Content-Type": "application/json"});
if (recordset != null)
{
console.log(JSON.stringify(recordset, null, 4));
response.write(JSON.stringify(recordset, null, 4));
}
response.end();
console.log();
});
}
http.createServer(onRequest).listen(8888);
console.log("Server has started!");
}
I use "HttpRequester" to post a request, and add attachment within in (small file) or use the content textbox to send data in it. In my server I get the request but no access to it's body. I tried:
console.log(request.body);
But it's undefined.
I tried to print all request to look for my data, but it's too long and I can't see all the request.
I tried other request because I thought "HttpRequester" may not send me the right request by a friend who sent it to me from the client.
How can I access the body of the request?
If you need to use the default http module you need to read the request body from the data stream:
if (request.method == 'POST') {
request.on('data', function(chunk) {
console.log("Received body data:");
console.log(chunk.toString());
});
}
I would recommend you to have a look at expressjs, it already features routing and has various body parser's for files/json etc.
I ajax an GET request in client side:
$.ajax({
url: '/update',
type: 'get',
data: {
"key": key,
"value": value
},
success: function (data, err) {
}
})
then at the node side, I want get the parameter
var showParam = function (req, res) {
if (req.body) {
for (var key in req.body) {
console.log(key + ": " + req.body[key]);
}
res.send({status:'ok',message:'data received'});
} else {
console.log("nothing received");
res.send({status:'nok',message:'no Tweet received'});
}
}
app.get('/update', function(req, res){
showParam(req, res);
})
The shell show the body is empty and undefined.
But when I change the get to post (both at the client side and server side), everything is ok, I can get the parameter correctly.
What's problem with my code? Do I miss something?
If you are issuing a GET request, the URL parameters are not part of the body, and thus will not be parsed by the bodyParser middleware.
To access the query parameters, just reference req.query
You can access your data for get request in server-side by using req.query.key and req.query.value.
In order to get params from bodyParser you must use POST not GET. Your ajax request and server calls must both use POST.
http://expressjs.com/api.html#req.body
app.post('/update', function(req, res){
showParam(req, res);
});
$.ajax({
url: '/update',
type: 'POST',
data: {
"key": key,
"value": value
},
success: function (data, err) {
}
});
To get the GET params, use the url module and use query = url.parse(req.url, true).query. query will contain an object with the values accessible via query.foo