I have been getting hanging requests, with only expressjs, on my windows 10 machine. The code I will post is the current version of the code; it was tried a) without async, and b) without redis anywhere and just the 'test' route. The request just hangs, whether called from Postman or accessed directly from a browser. Admin privileges were given with the same result.
const express = require('express')
import { createClient } from "redis"
import { UserApi } from "./api/users"
(async () => {
const app = express()
const client = createClient()
//Check redis
client.on('error', (err) => console.log('Redis Client Error', err))
//Connect to redis client
await client.connect()
//Create API instances
const ua = new UserApi(client)
//Initialize middleware\
app.use(express.json)
//Create routes
//test
app.get("/test", function(req, res) {
res.send("got")
})
//signup - creates user
app.post("/signup", async function(req, res) {
console.log("starting")
const u = {username: req.body.username, email: req.body.email, password: req.body.password}
console.log("why")
try {
console.log("trying")
const token = await ua.create(u)
res.send(token)
} catch (error) {
res.status(400).send(error)
}
})
app.listen(3000, () => {
console.log("server up")
})
}) ()
Related
Im learning to use JWT. I setup a very simple react app and an express server that uses a json file as database to try it but when i return a cookie via res.cookie the request is stuck on pending according to my browsers network tab.
This is how my server looks
const express = require("express");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const jwt = require("jsonwebtoken");
const { JsonDB, Config } = require("node-json-db");
require("dotenv").config();
const server = express();
server.use(express.json());
server.use(cors());
server.use(cookieParser());
const db = new JsonDB(new Config("db", true, false));
server.post("/login", async (req, res) => {
const { username, password } = req.body;
const data = await db.getData("/users");
const user = data.find((user) => {
return user.username === username && user.password === password;
});
if (!user) {
return res.status(403).json({
error: "invalid login",
});
}
const token = jwt.sign(user, process.env.MY_SECRET, { expiresIn: "1h" });
return res.cookie("token", token, { httpOnly: true });
});
server.get("/logout", (req, res) => {
console.log("cleared token");
return res.clearCookie("token");
});
server.listen(3000, () => {
console.log("server listening on port 3000");
});
And this is my request in my react app
const handleSubmit = async () => {
const username = usernameRef.current.value;
const password = passwordRef.current.value;
const response = await axios.post("http://localhost:3000/login", {
username: username,
password: password,
});
console.log(response);
};
I've tried changing the order of the middlewares around and adding next() at the end but didn't work. Sending data via res.send works just fine. I've worked with express about a year ago but never ran into this.
res.cookie only set cookie. It doesn't response to client. After res.cookie, use res.send, res.json or any method to response.
In my web app, I'm using express-jwt, but for some reason the secret refuses to be loaded and i do not understand why.
const express = require('express')
import { createClient } from "redis"
import { UserApi } from "./api/users"
const jwtExpress = require('express-jwt')
(async () => {
//load in dotenv
require('dotenv').config()
const app = express()
const client = createClient()
//Check redis
client.on('error', (err) => console.log('Redis Client Error', err))
//Connect to redis client
await client.connect()
//Create API instances
const ua = new UserApi(client)
//Initialize middleware
app.use(express.json())
app.use(jwtExpress({ secret: "test", algorithms: ['HS256']}).unless({path: ['/token', '/test']}));
//Create routes
//test
app.get("/test", function(req, res) {
res.send("got")
})
//signup - creates user
app.post("/signup", async function(req, res) {
const u = {email: req.body.email, password: req.body.password}
try {
const {token, refreshToken} = await ua.create(u)
res.send({token: token, refreshToken: refreshToken, user_email: u.email })
} catch (error) {
res.status(400).send({error: error.toString()})
}
})
//login - logs in user
app.post("/login", async function(req, res) {
const u = {email: req.body.email, password: req.body.password}
try {
const token = await ua.login(u)
res.send(token)
} catch (error) {
res.status(400).send({error: error.toString()})
}
})
//refresh - refreshes token
app.post('/refresh', async function (req, res) {
const u = {email: req.body.email, refresh: req.body.refreshToken}
try {
const token = await ua.token(u.email, u.refresh)
res.send(token)
} catch (error) {
res.status(400).send({error: error.toString()})
}
})
app.listen(3000, () => {
console.log("server up")
})
}) ()
Could the async function be a problem? This is a copy of the error I receive:
if (!options || !options.secret) throw new Error('secret should be set');
^
Error: secret should be set
at module.exports (C:\Users\user\Projects\music-app\backend\node_modules\express-jwt\lib\index.js:20:42)
When I m trying to test my GET API using postman it returns 200 but with an empty body, The data I'm expecting to get do not show up.
Find my server.js file and the screenshot of POSTMAN result
app.get('/api/articles/:name', async (req, res) => {
try {
const articleName = req.params.name;
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('my-blog');
const articleInfo = await db.collection('articles').findOne({ name: articleName })
res.status(200).json(articleInfo)
client.close()
}
catch (error) {
res.status(500).json({ message: 'error connecting to db', error })
}
})
here i have updated your code as below and please move your server.js outside of /src folder. its working now.
const express = require('express')
const bodyParser = require('body-parser')
const {MongoClient} = require("mongodb");
const url = 'mongodb://127.0.0.1:27017';
const app = express();
app.use(bodyParser.json());
app.get('/api/articles/:name', async (req, res) => {
try {
const articleName = req.params.name;
MongoClient.connect(url, async (err, db) => {
const client = db.db('article');
const articleInfo = await client.collection('articles').findOne({title: articleName})
res.send(articleInfo)
});
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error });
}
});
app.listen(8000, () => console.log('Listening on port 8000'));
my socket creates problem when frontend loads before the server,
My problems are
1.I get same the socketid from the cookies of multiple clients
2.I get only one client who is connected with multiple socketids from the server
3.When I get this problem, my API calls will not work and I won't get any data from my database
I also get this problem when I restart the server, and when I refresh the frontend multiple times with different clients
my server side code
const mongoose = require("mongoose");
express = require("express");
app = express();
bodyParser = require("body-parser");
cookieParser = require("cookie-parser");
cors = require("cors");
user = require("./routes/user");
message = require("./routes/message");
http = require("http");
server = http.createServer(app);
io = require("socket.io")(server);
var userdata = require("./controllers/user");
mongoose
.connect(process.env.DATABASE, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => {
console.log("DB CONNECTED");
})
.catch((err) => console.log(err));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(cors());
app.use(express.json());
app.use("/use", user);
app.use("/use", message);
let users = [];
io.on("connection", (socket) => {
socket.on("done", () => {
let userdata = require("./controllers/user");
console.log("connected");
userdata.userdata &&
users.push({ userid: userdata.userdata._id, socketid: socket.id });
console.log(users);
});
socket.broadcast.emit("message");
socket.on("more", function (c) {
console.log(c.a, c.b);
let d = users.find((s) => s.userid === c.b);
if (d) {
return io.to(d.socketid).emit("message", c);
}
});
socket.on("disconnect", () => {
console.log(socket.id);
if (users) {
for (let e = 0; users.length; e++) {
if (users[e] && users[e].socketid === socket.id) {
return users.splice(e, 1);
}
}
}
console.log(users);
return console.log("disconnected");
});
});
// app.use();
const port = process.env.PORT || 8000;
server.listen(port, () => {
console.log(`app is running at ${port}`);
});
I found that my problem is caused by userdata, when I had deleted everything related to userdata, I didn't get any problem even when the server is reloaded.
Here userdata comes from a middileware called isSignedIn,this middleware is called before every API call from this webpage, so userdata gets updated frequently by the frontend code.This is my isSignedIn function
exports.isSignedIn = async (req, res, next) => {
const header = req.headers["authorization"];
const token = header && header.split(" ")[1];
if (!token) return res.json("no token");
jwt.verify(token, "jsdhbcjsd", (err, User) => {
if (err) return res.json(`${err} not signedin`);
req.User = User;
exports.userdata = User;
next();
});
};
I tried to call isSignedIn() instead of importing userdata, which would be lot better, but I was getting an error from the headers, so I couldn't call this function.
error I get when I call this function isSignedIn()
Promise {
<rejected> TypeError: Cannot read property 'headers' of undefined
at exports.isSignedIn (D:\message\backend\controllers\user.js:86:22)
it tells about this line
const header = req.headers["authorization"];
I made sure that the socket gets connected in the frontend only after calling the APIs using await,so that the userdata gets updated before connecting to the socket.I had tested it in the console,socket gets connected only after calling APIs
async componentDidMount() {
//my API calls
await this.friends(token);
await this.findfriends(token);
//connect the socket
this.start();
this.recieve();
}}
My frontend code
const client = require("socket.io-client");
var socket
export default class Home extends Component {
constructor(props) {
super(props);
this.start = this.start.bind(this);
this.send = this.send.bind(this);
this.recieve = this.recieve.bind(this);
this.friends= this.friends.bind(this);
this.findfriends= this.findfriends.bind(this);
}
start(){
socket=client("http://localhost:8000");
}
send(){
socket.emit("more", c)
}
recieve(){
socket.on("message", c)
}
async componentDidMount() {
//my API calls
await this.friends(token);
await this.findfriends(token);
//connect the socket
this.start();
this.recieve();
}}
render(){
return(my data)
}
}
After thinking for a while about requesting headers,which isn't possible, I thought, why couldn't I get userid from the socket when just it gets connected, then I tried this code, it worked perfectly fine
client side
start = () => {
socket = client("http://localhost:8000");
socket.on("connect", () => {
return socket.emit("userinfo", this.state.User._id);
});
};
server side
socket.on("userinfo", function (user) {
users.push({ userid: user, socketid: socket.id });
console.log("C O N N E C T E D");
});
You can't reassign exports.userdata = User; in middleware. That will affect every single request that uses those exports so they will all end up looking at the same userdata, no matter which user they are. That's the source of your confusion. There's only one exports object for each module and everyone who uses that module sees the same exports object. So, you can't use exports for request-specific data.
I see you are already assigning req.User = User. That is an appropriate place to put request-specific data and other users of that data in the processing of the request should get the data from req.User, not from the exported object. That will keep the data separate for each request and each user.
I am trying to learn node.js and I am stuck trying to send the JSON to the browser, I have not tried to consume the REST service because apparently the JSON is not being sent, it does not appear in postman.
This is my code:
Database connections pool
const mysql = require('mysql');
const pool = mysql.createPool({
host: "localhost",
database: "dbname",
user: "root",
password: "",
debug: true
});
module.exports.pool = pool;
Index
const Joi = require('joi');
const connections = require('./connections')
const express = require('express');
const app = express();
app.use(express.json());
function getClients() {
return new Promise((resolve, reject) => {
connections.pool.getConnection((error, connection) => {
connection.query("select * from clientes", (error, rows) => {
if(error) {
reject(new Error);
}
else {
resolve(JSON.stringify(rows));
}
})
connection.release();
})
});
}
app.get('/', (req, res) => {
getClients().then((rows) => {console.log(rows)})
.catch(err => err);
console.log(res);
res.end();
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`listening on port ${PORT}`));
In this part:
getClients().then((rows) => {console.log(rows)})
It logs the correct JSON response at the end however it calls a lot my attention that I am getting a very long server response before the JSON string.
when I use res.send(rows) it displays nothing, postman gives me 200 response and blank page.
I literally started learning NODEJS 3 days ago and I have been stuck with this for one day :(
You are not sending any data in response.
res.send does not send JSON it sends only string use res.json()
app.get('/', (req, res) => {
getClients()
.then((rows) => res.json(rows))
.catch(err => res.status(400).json(err));
});