I am working on a web app project and for which i need to authenticate the user for some protected routes so i am using jwt tokens for this need.
Technologies used in project :-
frontend --> react
backend --> node, express
Node JS backend code.
const express = require('express');
const app = express();
const ProductModel = require('../Schemas/productSchema')
const product = ProductModel;
app.get('/', (req, res) => {
try {
product.find(function(err, data){
if(data){
res.cookie("test", "test1");
res.send(data);
}
else{
res.json({message : err});
}
})
} catch (error) {
res.json({message : error});
}
})
React frontend code.
here in this frontend code i am making a get request to the server using fetch
useEffect(() => {
async function fetchData(){
await fetch('http://localhost:5000/products')
.then(res => res.json())
.then(data =>{
// setProducts(data.data);
})
.catch(err => console.log(err))
}
fetchData();
}, [])
In the nodejs code i am sending cookie to the browser and for good the cookie is getting shown in the chrome devtool network
But cookie is not getting shown up in the browser->devtool->application->cookies
I don't know why this happening please submit the solutions with explanation.
First, I guess that u need to import the cookie parser
const cookieParser = require('cookie-parser')
app.use(cookieParser());
this lets you use the cookieParser in your application
And finally u can use it :
res.cookie(`...`);
Related
I have an api in express js that stores token in cookie on the client-side (react). The cookie is generated only when the user logins into the site. For example, when I test the login api with the postman, the cookie is generated as expected like this:
But when I log in with react.js then no cookie is found in the browser. Looks like the cookie was not passed to the front end as the screenshot demonstrates below:
As we got an alert message this means express api is working perfectly without any error!!
Here is my index.js file on express js that includes cookie-parser middleware as well
require("dotenv").config();
const port = process.env.PORT || 5050;
const express = require("express");
const app = express();
const cors = require("cors");
const authRouter = require("./routes/auth");
var cookieParser = require('cookie-parser')
connect_db();
app.use(express.json());
app.use(cookieParser())
app.use(cors());
app.use("/" , authRouter);
app.listen(port , () => {
console.log("Server is running!!");
})
Code for setting up the cookie from express api only controller
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require('bcrypt')
const login = async (req, res) => {
const { email, password } = req.body;
try {
const checkDetails = await User.findOne({ email });
if (checkDetails) {
const { password: hashedPassword, token, username } = checkDetails;
bcrypt.compare(password, hashedPassword, function (err, matched) {
if (matched) {
res.cookie("token", token, { expires: new Date(Date.now() + (5 * 60000)) , httpOnly: true }).json({ "message": "You logged in sucessfully!" });
} else {
res.status(500).json({ "message": "Wrong password" });
}
});
} else {
res.status(500).json({ "message": "Wrong email" });
}
} catch (error) {
console.log(error.message);
}
}
Here is the react.js code that I am using to fetch data from api without using a proxy in package.json file
if (errors.length === 0) {
const isLogin = await fetch("http://localhost:5000/api/login", {
method: "POST",
body: JSON.stringify({ email, password }),
headers: {
"Content-Type": "application/json"
}
});
const res = await isLogin.json();
if(res) alert(res.message);
}
I want to get to know what is the reason behind this "getting cookie in postman but not in the browser". Do I need to use any react package?
The network tab screenshot might help you.
If I see in the network tab I get the same cookie, set among the other headers
To my understanding, fetch doesn't send requests with the cookies your browser has stored for that domain, and similarly, it doesn't store any cookies it receives in the response. This seems to be the expected behaviour of fetch.
To override this, try setting the credentials option when making the request, like so:
fetch(url, {
// ...
credentials: 'include'
})
or, alternatively:
fetch(url, {
// ...
credentials: 'same-origin'
})
You can read more about the differences between the two here.
I got my error resolved with two changings in my code
In front end just added credentials: 'include'
fetch(url, {
method : "POST"
body : body,
headers : headers,
credentials: 'include'
})
And in back end just replaced app.use(cors()); to
app.use(cors({ origin: 'http://localhost:3000', credentials: true, exposedHeaders: ['Set-Cookie', 'Date', 'ETag'] }))
That's it got resolved, Now I have cookies stored in my browser!!! Great. Thanks to this article:
https://www.anycodings.com/2022/01/react-app-express-server-set-cookie-not.html
during development i also faced same things, let me help you that how i solve it,
Firstly you use proxy in your react package.json, below private one:-
"private": true,
"proxy":"http://127.0.0.1:5000",
mention the same port on which your node server is running
Like:-
app.listen(5000,'127.0.0.1',()=>{
console.log('Server is Running');
});
above both must be on same , now react will run on port 3000 as usual but now we will create proxy to react So, react and node ports get connected on same with the help of proxy indirectly.
Now, when you will make GET or POST request from react then don't provide full URL, only provide the path on which you wants to get hit in backend and get response,
Example:-
React side on sending request, follow like this:-
const submitHandler=()=>{
axios.post('/api/loginuser',
{mobile:inputField.mobile,password:inputField.password})
.then((res)=>{
console.log(res);
})
.catch((err)=>{
console.log(err);
})
}
Node side where it will hit:-
app.post('/api/loginuser', async(req,res)=>{
//Your Code Stuff Here
res.send()
}
on both side same link should hit, it is very important
it will 100%.
don't forget to mention
on node main main where server is listening
Its my first time using Express and MongoDB, i have created my Node server and connected it to my mongoDB database, but when i try to send an request from my html page to the server i get Error 405 method not allowed, following is my node.js server code
mongoose.connect('mongodb://localhost/userdatabase' ,{
useNewUrlParser: true,
useUnifiedTopology: true
})
const app = express()
app.use('/', express.static(path.join(__dirname, 'static')))
app.use(bodyParser.json())
const port = 5500
app.listen(port, () => {
console.log(`server is up at ${port}`)
})
app.post('/api/register', async(req, res) => {
const {username, password} = req.body
res.json({status: 'ok'})
try{
const response = await User.create({
username,
password
})
console.log('User created succesfully' , response)
}catch(error){
console.log(error)
}
})
and here is the function im trying to call to do the post request
const form = document.querySelector('#register')
form.addEventListener('submit', registerUser)
async function registerUser(event){
event.preventDefault()
const username = document.getElementById('username').value
const password = document.getElementById('password').value
const result = await fetch('/api/register', {
method: 'POST',
headers: {
'Content-Type' : 'application/json'
}, body: JSON.stringify({
username,
password
})
}).then(res => res.json())
}
basically i am creating an login system and try to register users, but for some reason i keep getting the error 405 when trying to call the Server, Note that for some reason it worked 3 times when i was trying earlier, I havent changed almost anything in the code but it just wont work, what it can be ? thanks in advance
You should tell in which port mongoDB would run.
const mongoose = require('mongoose');
main().catch(err => console.log(err));
async function main() {
await mongoose.connect('mongodb://localhost:27017/test');
}
I think you have to declare the server and port while calling the axios. The axios call should be - await fetch('localhost:5500/api/register'). It's searching for '/api/register' but didn't find anything. Hope this will solve your issue.
Issue solved : the html file wasn't in the folder 'static' 😅 probably i have moved it and didn't noticed, sorry for the question guys, if anyone have the same problem make sure to check it
I am trying to deploy reactjs & nodejs app to heroku.
I have successfully deployed frontend,but frontend is sending data to nodejs using localhost due to which when running app through heroku only frontend is working.
This code send data to nodejs.
saveUserJson = (User) =>{
const url = 'http://localhost:5000/write'
axios.post(url,User)
.then(response => {
//console.log(response);
});
}
This is nodejs code(ignore hostname in code).
const express = require('express');
const bodyParser = require('body-parser');
const fs = require('fs');
const morgan = require('morgan');
const cors = require('cors');
const jsonData = require('../src/descriptors/bnk48.json')
const app = express();
const port = 5000;
const hostname = '192.168.43.113';
app.use(bodyParser.json());
app.use(morgan('dev'));
app.use(cors());
app.get('/',(req,res) => res.status(200).send({
message: "Server is running..."
}));
const WriteTextToFileSync = (contentToWrite) => {
fs.writeFileSync('./src/descriptors/bnk48.json',contentToWrite,(err) =>{
//console.log(contentToWrite);
if(err) {
console.log(err);
}else {
console.log('Done writing to file successfully...')
}
})
}
const user = {
}
app.post('/write',(req,res,next) =>{
const user = {
"name": req.body[0].name,
"descriptors": req.body[0].descriptors
}
jsonData[user.name]=user
//console.log(req.body[0].descriptors)
const requestContent = JSON.stringify(jsonData,null,2);
WriteTextToFileSync(requestContent)
});
app.use((req,res,next) => res.status(404).send({
message: "Couldn't find specified route that was requested..."
}));
app.listen(port,hostname,()=>{
console.log(
`
!!! server is running..
!!! Listening for incoming requests on port ${port}
!!! Server running at http://${hostname}:${port}/
!!! http://localhost:5000
`
)
})
How can i change localhost so that while deploying it automatically chooses where to send data?
How can i change localhost so that while deploying it automatically chooses where to send data?
There are several ways to do this, but it's quite common to use environment variables for this purpose. These are set by environment, your development machine being one environment and your production site on Heroku being another environment. You could for example define the environment variable BACKEND_ROOT_URL to hold the schema and FQDN of your site, and make your axios call like this:
saveUserJson = (User) =>{
const url = `${process.env.BACKEND_ROOT_URL}/write`
axios.post(url,User)
.then(response => {
//console.log(response);
});
}
The build-time value of url will be different, depending on which environment you perform the build in.
Setting environment variables locally can be done in several ways. In a Bash shell you can set them manually like export BACKEND_ROOT_URL=http://localhost:5000. That get's boring quite fast though, so I would recommend you to check out dotenv which handles this for you efficiently.
Heroku has its own way of handling the setting of envvars - check the documentation here
I'm new to next.js so maybe I'm missing something very stupid. I want to use custom routes so I created a server.js file and changed my package.json command to node server.js. This is the entire server.js file:
const express = require("express");
const next = require("next");
const createLocaleMiddleware = require("express-locale");
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() => {
const server = express();
server.get("/", createLocaleMiddleware(), (req, res) => {
res.redirect(`/${req.locale.language}/home`);
});
server.get("/:lang/home", (req, res) => {
const actualPage = "/";
const queryParams = { locale: req.params.lang };
app.render(req, res, actualPage, queryParams);
});
server.listen(3000, err => {
if (err) throw err;
console.log("> Ready on http://localhost:3000");
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
I believe that according to the docs, this should work. I just want to render the index page with the users locale on the specified route ('/:lang/home'). I'm using react-intl for the i18n.
Now I get the following error in the console (client side):
It's in dutch but it's just saying it can't find any of the specified files. So now the HMR is not working anymore, routing is not working anymore (with Router.push). The only thing it does correctly is loading the index page (I can see it in the browser).
I also tried to enable and disable this flag from the docs:
module.exports = {
useFileSystemPublicRoutes: false
}
Sadly, no effect.
Am I missing something? Is it because I'm redirecting? Or is this not to way to handle routing? If someone could provide some pointers that would be great :)
Thanks in advance!
You are missing server.get('*', handle) as you can see in the custom server express example. This is absolutely required :)
I am a beginner in VueJs and Expressjs. I am trying to make frontend side by Vuejs and backend by ExpressJs. I send a post request to the backend (expressJs) and :
1- Response is undefined
2- At the same time I can see 2 requests in chrome development tools. One is Option and another one is Post.
3- With postman there is no problem at all.
Here is the code of app.js in express
console.log('Server is running')
const express = require('express'),
bodyParser = require('body-parser'),
cors = require('cors'),
morgan = require('morgan');
app = new express();
//Setup middleware
app.use(cors());
app.use(morgan('combined'))
app.use(bodyParser.json())
app.post('/register', (req, res, next) => {
res.send({
message: `Hello ${req.body.email}! your user was registered!`
})
});
app.listen(8081);
And here is the code in VueJs :
// Api Setting
import axios from 'axios'
export const HTTP = axios.create({
baseURL: `http://localhost:8081`
});
// AuthenticationService
import { HTTP } from '../services/Api'
export default {
register(credentials) {
HTTP.post('register', credentials);
}
}
// Register Component
export default {
data() {
return {
email: '',
password: ''
};
},
methods: {
async register() {
const response = await AuthenticationService.register({
email: this.email,
password: this.password
});
console.log(response); // the value is undefined
}
}
};
I really don't know what I missed here that I get an undefined response and 2 requests at the same time. I appreciate any hint.
Whole code on github repo : here
Maybe. Authentication.register is not returning anything or more specifically a Promise which should be used to populate const response in the await call.
Try returning something like so: return HTTP.post('register', credentials); inside register.
For this to work though, HTTP.post('register', credentials) should also return something.
I use JSON.stringify to send the data, you are sending the objects directly, so
register(credentials) {
HTTP.post('register', credentials);
}
becomes
register(credentials) {
HTTP.post('register', JSON.stringify(credentials));
}