I have a ExpressJS server and I would like to implement in Sessions however it doesn't seem to save the sessions.
The flow is to:
POST to /api/login
GET from /api/viewSession
However, the session['stuff'] returns undefined.
I suspected it might be because i'm trying to GET the session from a different URL. So I added a GET method to /api/login but it returned undefined too.
Could somebody point me in the right direction please? I'm a little lost after a few hours of Googling to no avail.
Here below is my code for index.js and my route api.js.
Also, I'm using
NPM - Version 8.3.1
Node - Version v16.14.0
npm i cors - Version 2.8.5
npm i express-session - Version 1.17.2
npm i express - Version 4.17.3
index.js
const express = require('express')
const formidable = require('express-formidable');
const cors = require('cors');
const session = require('express-session');
const api = require('./routes/api');
const app = express()
const port = 3000;
app.use(express.json());
app.use(formidable());
app.use(
cors({
origin: true,
optionsSuccessStatus: 200,
credentials: true,
})
);
app.options(
'*',
cors({
origin: true,
optionsSuccessStatus: 200,
credentials: true,
})
);
app.use(
session({
saveUninitialized: false,
secret: "anyrandomstring",
cookie: { maxAge: 36000000 }
})
);
//Routes
app.use('/api', api);
//Navigation
app.get('/', function (req, res) {
res.render('index');
res.send("Hi!");
})
//App Start
app.listen(port, () => {
console.log(`App Listening on port ${port}`);
})
api.js
"use strict";
const express = require("express");
let router = express.Router();
router
.route('/dump')
.post(async (req, res) => {
console.log(req.fields);
res.send({status: "ok"})
})
router
.route('/login')
.post(async (req, res) => {
//Saving in Session
req.session['stuff'] = "123456";
res.send("Ok");
})
router
.route('/viewSession')
.get((req, res) => {
console.log(req.session['stuff']);
res.send("ok");
})
module.exports = router;
Also, this is the way I send the POST/GET request
$.ajax({
url: "http://localhost:3000" + '/api/login',
type: "POST",
crossDomain: true,
dataType: "json",
data: {},
success: function (response) {
console.log(response);
}
})
If you're making cross-domain requests with XMLHttpRequest and you want to allow cookies to be set by the server handling the request, you need to set withCredentials : true.
Using jQuery:
$.ajax({
url: "http://localhost:3000" + '/api/login',
type: "POST",
crossDomain: true,
xhrFields: { withCredentials: true },
dataType: "json",
data: {},
success: function (response) {
console.log(response);
}
})
Related
I'm trying to fetch data from my Express API but I'm keep getting this error.
Firefox Console Error
Chrome Console Error
I have tried everything I find on internet.
I tried using different browser, browser extensions to bypass CORS check.
I thought maybe the issue is related to localhost, so I deployed it, but the same issue persisted.
I tried mockup API with the same frontend, and it fetches data just fine.
I tried manually adding Access-Control-Allow-Origin header on server side but did not work.
I also tried CORS middleware for Express and again did not work.
I'm getting proper responses with Postman just fine, but not within a browser.
This is my code on client side:
async create(visit) {
this.setState({visits: [...this.state.visits, {...visit}]})
fetch('http://localhost:8000/create-visit', {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
},
body: `{"params": ${JSON.stringify(visit)}}`
})
.then(resolve => resolve.json())
.then(result => {console.log(result)})
}
I also tried GET request with but no difference.
And this is my server side code:
const express = require('express')
const visitRouter = require('./routers/visits')
const cors = require('cors')
const PORT = process.env.PORT;
const app = express();
var corsOptions = {
credentials: true,
origin: "*",
preflightContinue: true,
allowedHeaders: 'GET,PUT,POST,DELETE,OPTIONS'
}
var logger = function(req, res, next) {
console.log(res)
next()
}
app.use(logger)
app.use(express.json())
app.use(visitRouter)
// app.use((req, res, next) => {
// res.append('Access-Control-Allow-Origin', ['*'])
// res.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
// res.append('Access-Control-Allow-Headers', 'Content-Type')
// next()
// })
// app.use(cors())
app.use(cors(corsOptions))
app.listen(PORT, () => {
console.log(`Listening from port: ${PORT}`)
})
Router:
const express = require('express')
const router = new express.Router()
const visitModel = require('../models/visits')
router.post('/create-visit', async (req, res) => {
try {
const params = req.body.params
console.log(params)
const newVisit = await visitModel.createVisit(params)
res.status(201).send(newVisit)
} catch (err) {
res.status(500).send(err)
}
})
I deployed my app on heroku, its partially functioning as i have "server" side code that authenticates users with mongoDB atlas and performs api requests to Yelp's API. My app authenticates users just fine, but when i make a request to get nearby places, I get this error in the console.
GET https://my-first-trip.herokuapp.com/category/21.3420389/-157.7992015/pizza 503 (Service Unavailable)
Here is the code for my server.js located in the root directory:
require('dotenv').config()
const express = require('express');
const app = express();
const cors = require("cors");
const axios = require('axios');
const mongoose = require("mongoose")
const User = require('./models/user')
const session = require('express-session')
const bcrypt = require('bcrypt')
const MongoStore = require('connect-mongo')
const saltRounds = 6
const path = require('path')
mongoose.connect(process.env.ATLAS_URI)
app.use(express.json());
app.use(cors({
origin: ["http://localhost:3000"],
methods: ["GET", "POST", "DELETE"],
credentials: true
}))
// app.use(express.urlencoded())
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: '',
resave: false,
saveUninitialized: true,
cookie: { secure: false },
store: MongoStore.create({
mongoUrl: process.env.ATLAS_URI,
// collectionName: 'users'
})
}))
app.use(express.static(path.join(__dirname, "client", "build")))
app.get("/category", (req, res) => {
const config = {
method: 'get',
url: '...' ,
headers: {
'Authorization': process.env.API_KEY
}
};
axios(config)
.then((response) => {
res.json(response.data)
// console.log(response.data);
})
.catch((error) => {
res.json(error) //this returns 'request failed with status code 400'
});
});
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});
app.listen(process.env.PORT || 5000);
so the only route that doesnt work is app.get("/category/:lat/:lng/:searchCategory". In the heroku cli, I get code=H12 and desc=Request timeout. im pretty confident my yelp api query is a quick and inexpensive one. Im not sure how to debug this further.
EDIT: solved... my config var in heroku had extra quotes in my key. I entered 'key123' instead of just key123. I wish there was a way to tell what my error was. status code 400 (failed request ) was too broad
You can use Heroku Logging to find out about your error in detail:
I always use
heroku logs -n 1000 --tail
Or you can also use add-ons like papertrail
Edit: Try hardcoding your API call variables.
Faced such a problem and can no longer solve it 2 days, please help.
There is a server on the nodejs:
index.js
const mongoose = require("mongoose");
const keys = require("./config/keys");
const app = require("./app");
const port = process.env.PORT || 3001;
mongoose
.connect(keys.MONGO_URL, { useNewUrlParser: true })
.then(() => {
app.listen(port, () => console.log(`Server started on port ${port}`));
console.log("Connected to" + " MongoDB");
})
.catch((error) => console.log(error));
app.js
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const morgan = require("morgan");
const passport = require("passport");
const authRoutes = require("./routes/auth");
const restaurantRoutes = require("./routes/restaurant");
const app = express();
app.use(passport.initialize());
require("./middleware/passport")(passport);
app.use(morgan("dev"));
app.use("/uploads", express.static("uploads"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cors());
app.use("/api/auth", authRoutes);
app.use("/api/restaurant", restaurantRoutes);
module.exports = app;
Nested Routes:
router.get(
"/",
passport.authenticate("jwt", { session: false }),
controller.getAll
);
router.get(
"/:id",
passport.authenticate("jwt", { session: false }),
controller.getById
);
router.post(
"/create",
passport.authenticate("jwt", { session: false }),
upload.single("image"),
controller.create
);
router.patch(
"/update",
passport.authenticate("jwt", { session: false }),
upload.single("image"),
controller.update
);
router.delete(
"/:id",
passport.authenticate("jwt", { session: false }),
controller.delete
);
There is a request from the front:
export function createNewRestaurant(restaurant, token) {
return {
type: CREATE_NEW_RESTAURANT,
payload: axios({
type: "POST",
url: "api/restaurant/create",
headers: {
Authorization: token,
},
data: JSON.stringify(restaurant),
})
.then((response) => {
console.log(response);
// return response.data;
})
.catch((error) => {
console.log({ error });
// return error.response.data;
}),
};
}
The problem is that POST doesn't even get from the server ...
There is no mention of it in the server console
If you remove the line from package.json client
"proxy": "http://localhost:3001/"
and write in the request
url: "http://localhost:3001/api/restaurant/create",
then in the server console we will see the OPTIONS request
OPTIONS /api/restaurant/create 204 0.135 ms - 0
I understand that the case is CORS, but I have it installed and in theory should work it all out, but how does this happen?
In postman, the request goes fine
I am currently having a problem with React and Express JS form submit function. It seems like my nodeJS running on port 5000 is receiving an empty object from my ReactJS running on port 8080 using fetch method.
React : Contact.js
handleSubmit(e)
{
e.preventDefault();
var data = {
name: this.state.name,
contact: this.state.contact,
email: this.state.email,
message: this.state.message,
}
var url = 'http://localhost:5000/api/insertUsers';
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
mode: 'no-cors',
body: JSON.stringify(data),
})
.catch((error) => {
console.log(error);
});
}
NodeJS : server.js
const express = require('express');
const { Client } = require('pg');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/api/insertUsers', function(req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
res.end(JSON.stringify(req.body, null, 2))
});
app.listen(5000, () => {
console.log('listening on port 5000');
});
Change the order of bodyparser middleware like this.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
You are sending a request with the content-type of 'application/json' but express is expecting a content-type of 'text/json'. Usually, when req.body is empty content-type is the first suspect you should be looking at.
I am ashamed that I struggled with this for hours. I still haven't gotten it to work with file uploads.
But I did get it to work with a normal form by encoding JSON and sending that along with axios, instead of fetch
My js code
var data = {
id: this.state.id,
}
console.log('data',data)
var bodyFormData = new FormData();
bodyFormData.set('id', this.state.id);
var url = ' http://localhost:3000/get-image-by-id';
console.log("bodyFormData: ", bodyFormData);
axios({
method: 'post',
url: url,
data: data,
// headers: {'Content-Type': 'multipart/form-data' }
headers: {'Content-Type': 'application/x-www-form-urlencoded' }
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});
Form Code
<form method="POST" onSubmit={this.handleSubmit} >
<label>
Transaction ID
<input
type="text"
name="id"
value={this.state.id}
onChange={this.handleInputChange}
/>
</label>
<button type="submit">Submit</button>
</form>
```
EDIT
fetch(url, {
method: 'POST',
body: JSON.stringify(data),
mode: 'no-cors'
}).then((result)=>{
console.log("output" + result.json());
})
.catch((error) => {
console.log(error);
});
EDIT 2
for backend, install cors and add the following lines before route.
var cors = require('cors')
app.use(cors())
EDIT 3
perform npm install morgan then copy these lines inside the code
var morgan = require('morgan');
app.use(morgan('dev'));
I didn't look at your code close enough. My bad
app.post('/api/insertUsers', function(req, res) {
res.setHeader('Content-Type', 'text/plain')
res.write('you posted:\n')
res.end(JSON.stringify(req.body, null, 2))
});
Should be
app.post('/api/insertUsers', function(req, res) {
res.json(req.body)
});
try using axios instead of fetch
I rewrote ur code like this and it works perfectly
server
const express = require('express');
const { Client } = require('pg');
const bodyParser = require('body-parser');
const app = express();
const cors = require("cors");
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/insertUsers', function(req, res) {
// console.log(req);
console.log(req.body);
res.send(req.body);
});
app.listen(3001, () => {
console.log('listening on port 3001');
});
react (ensure you have axios installed)
handleSubmit(e){
e.preventDefault();
var data = {
name: "zadiki",
contact: "0702002109",
email: "zadiki",
message: "test",
}
console.log("wow");
var url = ' http://localhost:3001/api/insertUsers';
axios.post(url,data)
.then(response=>console.log(response))
.catch(e=>console.log(e))
}
Hello I ended up getting mine working after I ran into the same problem.
I noticed your react code has "mode: 'no-cors'," that was causing problems with mine so I removed it.
-------- Below is my handle submit code for React ------------
const handleSubmit = (event) => {
event.preventDefault();
const url = "http://localhost:3001/register"
const options = {
method: "POST",
body: JSON.stringify(formData),
headers: {
"Content-Type": "application/json"
}
}
fetch(url, options)
.then(res => res.json())
.then(res => console.log(res))
}
I used express.json instead of bodyParser. You also had a typo in your express code, it should say res.send instead of res.end
--------- Below is my Node Express Code -----------
const express = require('express');
const app = express();
const cors = require('cors');
const multer = require('multer');
// Middlewares
app.use(cors({ origin: 'http://localhost:3000', }))
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(multer().array());
app.post('/register',(req, res) => {
console.log(req.body)
res.status(200)
.json({status:"Success", data:{body: req.body })
});
app.listen(3001, () => console.log(`Running on 3001`))
I was able to send form data using postman and react using the code above. Feel free to change it to accommodate your needs.
I'm trying to deplay an SSR nuxt-legacy-edge project on a firebase Hosting.
Every things work fine in dev mode (npm run dev).
I'm using serverMiddleware /api defined in nuxtconfig.js
serverMiddleware: [
bodyParser.json(),
session({
secret: 'amdskfmdlkfdklfndfmdfndsmfndfnejnjheheuewytwgssa',
resave: true,
saveUninitialized: false,
cookie: { maxAge: (20 * 60 * 1000), secure: false }
}),
//{ path: '/api', handler: '~/api/index.js' },
'~/api'
]
and my /api/index.js is
const express = require('express')
const bodyParser = require('body-parser');
const router = express.Router()
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json({ limit: '50mb' }));
app.use(bodyParser.urlencoded({ extended: false }));
router.use((req, res, next) => {
Object.setPrototypeOf(req, app.request)
Object.setPrototypeOf(res, app.response)
req.res = res
res.req = req
next()
})
router.post('/confirmlogin', (req, res) => {
console.log('[API] - LOGIN POST', req.body.role)
req.session.userId = req.body.uid
req.session.role = req.body.role
req.session.token = req.body.token
req.session.profile=req.body.profile
res.cookie('access_token', req.body.token, {
maxAge: 3600000,
httpOnly: true
}) /* 1 hour */
return res.json({
status: 'success'
})
})
router.post('/confirmlogout', (req, res) => {
console.log('[API] - LOGOUT POST')
delete req.session.userId
delete req.session.role
delete req.session.token
delete req.session.profile
res.clearCookie('access_token');
return res.json({
status: 'success'
})
})
app.use('/', router);
module.exports = {
path: '/api',
handler: router
}
The firebase functions is defined as:
const functions = require('firebase-functions');
const { Nuxt } = require('nuxt-legacy-edge');
var express =require("express");
var app=express();
const config = {
dev: false,
buildDir: '.nuxt',
};
const nuxt = new Nuxt(config);
exports.webaffitto = functions.https.onRequest((req, res) => nuxt.render(req, res));
As shown in route api/confirmlogin and api/confirmlogout works fine in dev mode but if put in production using command
firebase serve --only functions,hosting or
using
firebase deploy
seem those routes are missing and I obtain a 404 (non found).
Help is appreciated.