In my small node.js application, using express, I wanted to log all the incoming requests, so I ended up with this:
var bodyParser = require('body-parser');
module.exports = function(app) {
app.set("port", 50001);
app.set("json spaces", 2);
app.use(bodyParser.json());
app.use(function (error, req, res, next) {
app.logger.info("received from "+req.get("X-Forwarded-For")+" : "+req.method+" "+req.originalUrl+" (Authorization: "+req.get("Authorization")+")");
//does not work if json is malformed
//app.logger.info("content :"+JSON.stringify(req.body));
if (error /*instanceof SyntaxError*/) {
res.status(400);
app.logger.error(error);
res.json({ error:{msg: error.message}});
} else {
next();
}
});
app.use(app.auth.initialize());
};
Unfortunately, I only get the logs via the app.logger.info line when there's an error (in my case a malformed JSON string in the body). What am I missing here?
Expressjs adapts its functionality based on what type of callback you give it (this is not common in JS libraries so it is not surprising that people get confused by it).
If you do this where your callback has four arguments:
app.use(function(error, req, res, next) {...});
then Express assumes this is an error-only middleware handler and will only be called when there are errors. In the express doc, see the section labeled Error-handling middleware. Note this specific part of that page:
Define error-handling middleware functions in the same way as other
middleware functions, except with four arguments instead of three,
specifically with the signature (err, req, res, next)):
And, here's a whole section of the documentation devoted to error handling middleware.
If you use just three arguments:
app.use(function(req, res, next) {...});
then, it is a normal middleware that is called when there are not errors. I'm not sure if they provide a single way to get both. But, certainly as a workaround, you could put your logging code into a function and then call that function from two separate middleware handlers, one for errors and one for non-errors.
Use morgan https://github.com/expressjs/morgan
Install morgan
$ npm install morgan
Include morgan in the index.js or app.js or server.js file (The file that pointed by the script tag in the package.json)
var morgan = require('morgan')
Then add below before all the app call.
app.use(morgan('combined'))
Complete example
var express = require('express')
var morgan = require('morgan')
var app = express()
app.use(morgan('combined'))
app.get('/', function (req, res) {
res.send('hello, world!')
})
A sample output line looks like this:
::1 - - [31/May/2021:09:03:14 +0000] "GET / HTTP/1.1" 200 2078 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
DEBUG='*' or DEBUG='express:router' environment variable
It does not show a lot of information about the request, but it does show the path and method, which might be enough for basic applications, and is convenient as it does not require any extra setup.
DEBUG='*' enables all logs and is slightly easier to type:
DEBUG='*' ./app.js
or the more specific DEBUG='express:router' is what you will generally want in a complex application with a lot of middleware, otherwise the DEBUG='*' could produce mountains of output:
DEBUG='express:router' ./app.js
E.g. with the hello world:
#!/usr/bin/env node
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Then as I play on the browser with different URLs I can see logs such as:
express:router dispatching GET / +3m
express:router query : / +0ms
express:router expressInit : / +0ms
express:router dispatching GET /asdf +10s
express:router query : /asdf +0ms
express:router expressInit : /asdf +0ms
finalhandler default 404 +3m
express:router dispatching GET /asdf?qwer=zxcv +17s
express:router query : /asdf?qwer=zxcv +0ms
express:router expressInit : /asdf?qwer=zxcv +0ms
finalhandler default 404 +17s
Documentation at: https://expressjs.com/en/guide/debugging.html
Tested on express 4.17.1.
npm install body-parser
npm install morgan-body
and use this snippet,
const express = require('express')
const morganBody = require("morgan-body")
const bodyParser = require("body-parser")
const app = express()
const port = 8888
// must parse body before morganBody as body will be logged
app.use(bodyParser.json());
// hook morganBody to express app
morganBody(app, {logAllReqHeader:true, maxBodyLength:5000});
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
You can just use grackle_tracking npm library to easily log all your traffic out to the console or log it to your database - also tracks uncaugt/caught errors - you can toggle it on/off easily for different environments as well since it's just
grackle_tracking.configure({...configuration...});
app.use(grackle_tracking.track);
so you can comment out both or just the bottom line for environments/users you don't want to track
https://www.getgrackle.com/libraries#grackle_tracking_overview
You could use try/catch
try {
var jsonBody = JSON.stringify(req.body);
app.logger.info("content :" + jsonBody);
} catch (err) {
app.logger.error("content error, error type: invalid json, error msg:" + err);
}
Related
In my cloud function:
const app = express();
app.use(multer().array());
app.post("/", (req, res) => {
console.log("hit", req.body.from);
console.log("hit", req.body.from);
return res.sendStatus(200);
});
const emailInboundWebhook = functions.https.onRequest(app);
module.exports = {
emailInboundWebhook
}
I get this in logs:
i functions: Beginning execution of "emailInboundWebhook"
> hit undefined
> hit undefined
i functions: Finished "emailInboundWebhook" in ~1s
But when the same endpoint served as an express app(outside cloud functions):
const express = require("express");
const app = express();
const multer = require('multer');
app.get("/", async (req, res) => {
res.status(200).json({foo: "Bar"});
})
app.use(multer().array());
app.post("/webhook", async (req, res) => {
console.log("hit",req.body.to);
console.log("hit",req.body.from);
res.sendStatus(200);
});
app.listen(80, () => {
console.log("App listening on 80");
})
Gives this:
hit a#some-email-inbound.some.url
hit Rahul Priyadarsi <myemailid#gmail.com>
The two results are for same email sent and these functions are fired as sendgrid webhooks which send multipart/form-data POST requests that contain details of the email sent to a#some-email-inbound.some.url from myemailid#gmail.com
I have no idea as to why the two results are different(I am testing them via ngrok and since the console log lines run, clearly the function is hit).
I had the same problem.
Take a look in this issue: https://github.com/expressjs/multer/issues/572
Switch from Multer to Busboy, is also a good option.
One thing: In this situation use https.Request (from cloud-functions) instead of Request from express.
I need to save the recent activity of a user in my system. Any idea how I can implement this?
Links to any articles?
Im using ExpressJS running on node as the server.
Thanks in advance.
It depends which actions should be saved as user activity.
To handle GET / POST requests:
Create MySQL database named «activity» with the table «requests» in MySQL Workbench like this:
Install an official MySQL connector by typing
npm install #mysql/xdevapi --save --save-exact
Open your index.js and put something like this:
const express = require('express');
const mysqlx = require('#mysql/xdevapi');
const app = express();
function log(url) {
mysqlx.getSession('dbLogin:dbPassword#localhost:33060')
.then(session => {
session
.getSchema('activity')
.getTable('requests')
.insert([ 'username', 'url' ])
.values([ 'User', url ])
.execute();
});
}
app.get('/', (req, res) => {
log(req.url);
res.sendFile(__dirname + '/index.html');
});
app.get('/info', (req, res) => {
log(req.url);
res.sendFile(__dirname + '/info.html');
});
app.listen(3000);
For more detailed information like mouse / keyboard events, you can send POST request with AJAX (see this answer for details) or use WebSockets
I am using create-react-app.
When you go to localhost:3001/test - it does serve up the HTML. But all you see is an empty page because nothing in the id "root" is rendered.
This is the code I have in my server:
app.get('/test', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
})
and my HTML is close to this:
<body>
<div id="root"></div>
</body>
You have to set the location of the static files. For example if you use environment variable.
if(process.env.ENV === 'prod'){
app.use(express.static('client/build'));
const path = require('path');
app.get('/test', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
})
}
Also, do make sure to run npm run build in order to create all the necessary files for deployment.
Based on the few details provided, I'll give a checklist
1- Make sure you have root in this part of your code
ReactDOM.render(<YourApp />, document.getElementById('root'));
2- In your console, do you have any error messages similar to this?
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
...Then your are just simply not receiving your data from the server because of CORS issues. Use this: CORS
3- Double check that your server that does the res.sendFile is running properly, check your terminal to check for errors like "file not found" or similar issues.
4- This works (I just tried it), try it in the same directory as your current server. Paste the code in testNode.js and run node testNode.js then visit http://localhost:3003/test
const express = require('express')
const app = express()
const port = 3003
app.get('/test', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
})
app.get('/', (request, response) => {
response.send('Hello from Express!')
})
app.listen(port, (err) => {
if (err) {
return console.log('something bad happened', err)
}
console.log(`server is listening on ${port}`)
})
5- Is the public/ folder readable? Does it have the right permissions? Try a chmod -R 777 public/ (change it back later)
I have a simple server where i just prints a json to the screen when its posted. This is my code:
/*jslint node:true*/
var express = require('express');
var app = express();
app.use(express.json());
app.use(app.router);
app.post('/event', function (res, req) {
//'use strict';
console.log(req.body);
});
app.listen(3000);
Then i put a JSON to the server with curl:
curl -X POST -H "Content-Type: application/json" -d '{"username":"xyz","password":"xyz"}' http://localhost:3000/event
But the server just prints undefined
What am i doing wrong?
you haven't defined usage of
express.bodyParser()
it has to be done like this:
app.use(express.bodyParser());
live example:
module routes file
exports.post = function(req, res){
console.log(req.body);
//res.render('index', { title: 'Express' });
};
application:
app.post('/post', routes.post);
fiddler request:
from comments: in case you have latest libs, you should take into account that bodyParser is deprecated from Connect 3.0. appropriate thread: How to get rid of Connect 3.0 deprecation alert?
I just figured out what the problem is. It should be:
function (req, res)
and not:
function (res, req)
since the first parameter is the request and the second is the response.
I'm sending the following JSON string to my server.
(
{
id = 1;
name = foo;
},
{
id = 2;
name = bar;
}
)
On the server I have this.
app.post('/', function(request, response) {
console.log("Got response: " + response.statusCode);
response.on('data', function(chunk) {
queryResponse+=chunk;
console.log('data');
});
response.on('end', function(){
console.log('end');
});
});
When I send the string, it shows that I got a 200 response, but those other two methods never run. Why is that?
I think you're conflating the use of the response object with that of the request.
The response object is for sending the HTTP response back to the calling client, whereas you are wanting to access the body of the request. See this answer which provides some guidance.
If you are using valid JSON and are POSTing it with Content-Type: application/json, then you can use the bodyParser middleware to parse the request body and place the result in request.body of your route.
Update for Express 4.16+
Starting with release 4.16.0, a new express.json() middleware is available.
var express = require('express');
var app = express();
app.use(express.json());
app.post('/', function(request, response){
console.log(request.body); // your JSON
response.send(request.body); // echo the result back
});
app.listen(3000);
Updated for Express 4.0 - 4.15
Body parser was split out into its own npm package after v4, requires a separate install npm install body-parser
var express = require('express')
, bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.post('/', function(request, response){
console.log(request.body); // your JSON
response.send(request.body); // echo the result back
});
app.listen(3000);
For earlier versions of Express (< 4)
var express = require('express')
, app = express.createServer();
app.use(express.bodyParser());
app.post('/', function(request, response){
console.log(request.body); // your JSON
response.send(request.body); // echo the result back
});
app.listen(3000);
Test along the lines of:
$ curl -d '{"MyKey":"My Value"}' -H "Content-Type: application/json" http://127.0.0.1:3000/
{"MyKey":"My Value"}
For Express v4+
install body-parser from the npm.
$ npm install body-parser
https://www.npmjs.org/package/body-parser#installation
var express = require('express')
var bodyParser = require('body-parser')
var app = express()
// parse application/json
app.use(bodyParser.json())
app.use(function (req, res, next) {
console.log(req.body) // populated!
next()
})
For those getting an empty object in req.body
I had forgotten to set
headers: {"Content-Type": "application/json"}
in the request. Changing it solved the problem.
#Daniel Thompson mentions that he had forgotten to add {"Content-Type": "application/json"} in the request. He was able to change the request, however, changing requests is not always possible (we are working on the server here).
In my case I needed to force content-type: text/plain to be parsed as json.
If you cannot change the content-type of the request, try using the following code:
app.use(express.json({type: '*/*'}));
Instead of using express.json() globally, I prefer to apply it only where needed, for instance in a POST request:
app.post('/mypost', express.json({type: '*/*'}), (req, res) => {
// echo json
res.json(req.body);
});
const express = require('express');
let app = express();
app.use(express.json());
This app.use(express.json) will now let you read the incoming post JSON object
Sometimes you don't need third party libraries to parse JSON from text.
Sometimes all you need it the following JS command, try it first:
const res_data = JSON.parse(body);
A beginner's mistake...i was using app.use(express.json()); in a local module instead of the main file (entry point).