CORS error while performing stripe checkout - node.js

I am working on a stripe checkout project but got stuck when I was not able to redirect to the stripe checkout page because of the cors error. My react frontend is running at localhost 3000 and express backend at localhost 5000. Here is how I am setting headers and using cors in my server.js :
if (process.env.NODE_ENV === 'development') {
app.use(cors({
credentials: true,
origin: process.env.CLIENT_URL
}))
app.use(morgan('dev'))
}
app.use(function(req, res, next) {
res.setHeader("Access-Control-Allow-Credentials", true);
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
res.setHeader('X-Frame-Options', 'sameorigin');
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, multipart/form-data");
res.setHeader("Access-Control-Allow-Methods", "HEAD,GET,POST,DELETE,OPTIONS,PUT");
next();
});
Here is my stripe.route.js :
const express = require('express')
const router = express.Router()
const Stripe = require('./../controllers/stripe.controller');
router.post('/checkout' , async(req,res) => {
const product = req.body.body;
console.log(product);
try
{
const session = Stripe.createCheckoutSession(product)
return res.send(session)
}
catch(e)
{
console.log(e);
res.status(400)
return res.send({
error: {
message: e.message
}
})
}
})
module.exports = router;
Here is my stripe.controller.js:
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY)
const createCheckoutSession = async(plan) => {
const session = await stripe.checkout.sessions.create({
success_url: `http://localhost:3000/success`,
cancel_url: `http://localhost:3000/fail`,
payment_method_types: ['card'],
line_items: [
{price: plan, quantity: 1},
],
mode: 'subscription',
});
return session;
}
module.exports = {
createCheckoutSession
}
Here is my react fronend page :
import React, { useRef } from "react";
import { isAuth } from "../helpers/auth";
import { useNavigate } from "react-router-dom";
import axios from 'axios';
import styles from "./Pricing.module.scss";
export const Pricing = () => {
const buttonValue = useRef();
const navigate = useNavigate();
const setBtnValue = (e) => {
buttonValue.current = e.target.value;
};
const checkoutHandler = async (e) => {
const btnValue = buttonValue.current;
console.log(btnValue);
const res = await axios
.post( 'http://localhost:5000/api/checkout' , {
method: "POST",
headers: {
"Content-Type": "application/json",
},
withCredentials: true,
credentials: 'same-origin',
body:
btnValue,
})
const url = res.url
window.location.href = url
};
return (
<div className={styles.container}>
<h2 className={styles.heading}>Choose</h2>
<div className={styles.priceRow}>
<div className={styles.priceCol}>
<p>Starter</p>
<h3>
50$ <span> / month</span>
</h3>
<ul>
<li>1 Website</li>
<li>10 GB Disk Space</li>
<li>Free Email Address</li>
<li>No SSL certificate</li>
<li>Limited Support</li>
</ul>
<form onSubmit={checkoutHandler}>
<button
value="price_1"
type="submit"
className="btn"
name="product"
onClick={setBtnValue}
>
Upgrade Now
</button>
</form>
</div>
</div>
</div>
);
};

you can send back session.url from backend , and then from front end you redirect using window.location.replace , and it will work

Related

Access to XMLHttpRequest blocked by CORS when sending data from front-end to back-end using POST

Here is a bit of a background: I am making a full stack to-do list application. The front-end is based on React and Bootstrap. The backend is using Express, Node and MongoDB. The problem is that when I'm fetching the data from MongoDB using GET, I can view it on frontend. But when I'm sending the data using POST, I get this error:
Access to XMLHttpRequest at 'http://localhost:5035/api/todos' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I'm adding the required code files here.
Frontend
TodoTask.js
// Handles displaying components related to todo task list
import React, { useState, useEffect } from "react";
import TodoForm from "./TodoForm";
import TodoUpdate from "./TodoUpdate";
import axios from "axios";
function TodoTask() {
//for the list of tasks
const [todos, setTodos] = useState([]);
//add task in the list of tasks
const addTodo = async todo => {
//check for empty input
if (!todo.text || /^\s*$/.test(todo.text)) {
return
}
const newTodos = [todo, ...todos];
setTodos(newTodos);
console.log(todos);
try {
await axios.post("http://localhost:5035/api/todos", {
todo
});
} catch (error) {
console.log(error);
}
}
const ViewAllTodos = () => {
useEffect(() => {
getAllTodo();
}, []);
}
const getAllTodo = async () => {
const response = await axios.get("http://localhost:5035/api/todos");
setTodos(response.data.Todo);
console.log(response.data.Todo);
}
const updateTodo = (todoId, newValue) => {
if (!newValue.text || /^\s*$/.test(newValue.text)) {
return
}
setTodos(prev => prev.map(item => (item.id === todoId ? newValue : item)))
}
const removeTodo = id => {
const remove = [...todos].filter(todo => todo.id !== id);
setTodos(remove);
}
const completeTodo = id => {
let updatedTodos = todos.map(todo => {
if (todo.id === id) {
todo.isComplete = !todo.isComplete;
}
return todo;
});
setTodos(updatedTodos);
}
const [message, setMessage] = useState('');
return (
<div id="container">
<h1 className="display-1">My To Do List Application</h1>
<p className="lead">This is a basic to do list application with complete frontend and backend configuration. For details, check ReadMe.md of this project.</p>
{/* calling the form component to show a text field */}
<label htmlFor="formGroupExampleInput">Enter your to do here:</label>
<TodoForm onSubmit={addTodo} />
{/* checking if the list is empty, otherwise list all the todos with update and delete button */}
{todos.length === 0 ?
<p className="lead">The list is empty!</p> :
<TodoUpdate todos={todos} completeTodo={setTodos} removeTodo={removeTodo}
updateTodo={updateTodo} />
}
{/* {todos.length === 0 ? <p>Empty</p> :
todos.map((todo, index) => (
<tr key={todo._id}>
<td>{todo.priority}</td>
<td>{todo.todo}</td>
</tr>
))
} */}
</div>
)
}
export default TodoTask;
Backend:
MongooseServer.js
// import dependencies
const express = require('express');
var bodyParser = require('body-parser');
const mongoose = require('mongoose');
const router = require('./routers/routes');
const cors = require('cors');
// const dbUrl = require('./config/db.config/url')
// set up dependencies
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/api/', router);
const corsOptions ={
origin:'http://localhost:3000',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
methods: "GET, POST"
}
app.use(cors(corsOptions));
//app.use(cors());
// app.use(cors({
// origin: 'http://localhost:3000',
// }))
// set up mongoose
mongoose.connect("mongodb://127.0.0.1:27017/mytodolist")
.then(()=> {
console.log('Database connected');
})
.catch((error)=> {
console.log('Error connecting to database');
});
// set up port
const port = 5035;
// set up route
app.get('/', (req, res) => {
res.status(200).json({
message: 'Welcome to todo list',
});
});
app.listen(port, () => {
console.log(`Our server is running on port ${port}`);
});
Model.js
const mongoose = require("mongoose");
const MyTodoListSchema = new mongoose.Schema({
taskId: {
type: Number,
required: true,
unique: true
},
todo: {
type: String,
default: "",
required: true
},
priority: {
type: String,
default: "high",
required: true
},
});
const MyTodoList = mongoose.model("MyTodoList", MyTodoListSchema);
module.exports = MyTodoList;
Controller.js
// import mongoose from 'mongoose';
const mongoose = require('mongoose')
// import {MyTodoList} from '../models/model';
const MyTodoList = require('../models/model');
exports.createTodo = (req, res) => {
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
next();
});
const todo = new MyTodoList({
taskId: req.body.taskId,
todo: req.body.todo,
priority: req.body.priority,
});
return todo
.save()
.then((newTodo) => {
return res.status(201).json({
success: true,
message: 'New todo list created successfully',
MyTodoList: newTodo,
});
})
.catch((error) => {
res.status(500).json({
success: false,
message: 'Server error. Please try again.',
error: error.message,
});
});
}
//get all todos
exports.getAllTodo = (req, res) => {
res.setHeader("Access-Control-Allow-Origin", "*")
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Max-Age", "1800");
res.setHeader("Access-Control-Allow-Headers", "content-type");
res.setHeader( "Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, PATCH, OPTIONS" );
MyTodoList.find()
.select('taskId todo priority')
// .then( () => {
// res.setHeader("Access-Control-Allow-Origin", "*")
// res.setHeader("Access-Control-Allow-Credentials", "true");
// res.setHeader("Access-Control-Max-Age", "1800");
// res.setHeader("Access-Control-Allow-Headers", "content-type");
// res.setHeader( "Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, PATCH, OPTIONS" );
// })
.then((allTodo) => {
// const response = res.status(200).json( {
// success: true,
// message: 'A list of all todos',
// Todo: allTodo
// });
return res.status(200).json({
// success: true,
// message: 'A list of all todos',
Todo: allTodo
});
// return response;
})
.catch((err) => {
res.status(500).json({
success: false,
message: 'Server error. Please try again.',
error: err.message,
});
});
}
// module.exports = {createTodo, getAllTodo}
Route.js
const express = require("express");
const cors = require("cors");
const todolist_controller = require('../controllers/controller')
const app = express();
const router = express.Router();
router.post('/todos', todolist_controller.createTodo);
router.get('/todos', todolist_controller.getAllTodo);
module.exports = router;
Please guide me on what I'm doing wrong here.
The POST is working fine with Postman. I'm using the MVC pattern for the application. Also, the frontend and backend are two separate directories inside one main directory. Both are running on different ports. Frontend is running on port 3000 and backend on port 5035.
TIA! I'm stuck on this for day. Please help out here!
If you would like to whitelist for all API endpoints then cors middleware must be called before your route(and this recommended also) like following
const app = express();
const corsOptions ={
origin:'http://localhost:3000',
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200,
methods: "GET, POST"
}
app.use(cors(corsOptions));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use('/api/', router); // cors middleware must call before this line
Just use the cors middleware at the root of your api project with express for instance :
const cors = require('cors');
app.use(cors());

Fetch API giving Network request failed Expo App Nodejs

I have written an API in Nodejs which helps in reset password using Mysql database.It is working fine in Postman.I have called this API in Expo IOS App.But I am getting Network request failed error. Below is the Node js program:
app.js:
var express = require('express');
var path = require('path');
var connection = require('./database.js');
var nodemailer = require('nodemailer');
const bcrypt = require("bcryptjs")
var randtoken = require('rand-token');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var flash = require('express-flash');
var session = require('express-session');
var bodyParser = require('body-parser');
const createError = require('http-errors');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
var connection = require('./database.js');
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({extended: false}))
//send email
function sendEmail(email, token) {
var email = email;
var token = token;
var mail = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'c***********#gmail.com', // Your email id
pass: '**********' // Your password
}
});
var mailOptions = {
from: 'poornima#abccompany.com',
to: email,
subject: 'Reset Password Link - ABCCompany.com',
html: '<p>You requested for reset password, kindly use this link to reset
your password</p>'
};
mail.sendMail(mailOptions, function(error, info) {
if (error) {
console.log(1)
} else {
console.log(0)
}
});
}
app.post('/reset-password-email', function(req, res, next) {
var email = req.body.email;
console.log('email from api '+email);
connection.query('SELECT * FROM JTGDB.UserInfo WHERE email ="' + email + '"',
function(err, result) {
if (err) throw err;
var type = ''
var msg = ''
console.log(result[0]);
if (result[0].Email.length > 0) {
var token = randtoken.generate(20);
var sent = sendEmail(email, token);
if (sent != '0') {
var data = {
token: token
}
connection.query('UPDATE JTGDB.UserInfo SET ? WHERE email ="' + email + '"', data,
function(err, result) {
if(err) throw err
})
type = 'success';
msg = 'The reset password link has been sent to your email address';
} else {
type = 'error';
msg = 'Something goes to wrong. Please try again';
}
} else {
console.log('2');
type = 'error';
msg = 'The Email is not registered with us';
}
res.redirect('/');
});
})
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: '123458cat',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
app.use(flash());
app.use('/', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(4000, function () {
console.log('Node app is running on port 4000');
});
module.exports = app;
Below is the IOS App ForgetPassword Screen page:
ForgetPasswordScreen.js:
import React, { Component, Fragment, useState } from "react";
import { View, Text,SafeAreaView, Image, StyleSheet } from "react-native";
import { Formik } from "formik";
import * as Yup from "yup";
import FormInput from "../../components/UI/FormInput";
import FormButton from "../../components/UI/FormButton";
import ErrorMessage from "../../components/UI/ErrorMessage";
import * as authActions from '../../store/actions/auth';
import {useDispatch} from "react-redux";
import Toast from 'react-native-root-toast';
const validationSchema = Yup.object().shape({
email: Yup.string()
.label("Email")
.email("Enter a valid email")
.required("Please enter a registered email"),
});
const ForgotPasswordScreen = props => {
const [isLoading,setIsLoading] = React.useState(false);
const [error, setError] = React.useState('');
const dispatch = useDispatch();
const handlePasswordReset = async (values, actions) => {
const { email } = values;
console.log('email is '+email);
let action
action = authActions.resetpassword(
email
);
setError(null);
setIsLoading(true);
try{
await dispatch(action);
props.navigation.navigate("Login");
} catch (error) {
actions.setFieldError("general", error.message);
}
};
return (
<SafeAreaView>
<View style={styles.emailiconview}>
<Image source={require('../../assets/reset_email.png')} />
</View>
<View style ={styles.instrview1}>
<Text>
Please enter your registered email address below to
</Text>
</View>
<View style={styles.instrview2}>
<Text>receive password reset instruction</Text>
</View>
<View style={styles.emailinputview}>
<Formik
initialValues={{ email: "" }}
onSubmit={(values, actions) => {
handlePasswordReset(values, actions);
}}
validationSchema={validationSchema}
>
{({
handleChange,
values,
handleSubmit,
errors,
isValid,
touched,
handleBlur,
isSubmitting,
}) => (
<Fragment>
<FormInput
name="email"
value={values.email}
onChangeText={handleChange("email")}
placeholder="Enter email"
autoCapitalize="none"
iconName="ios-mail"
iconColor="blue"
onBlur={handleBlur("email")}
/>
<ErrorMessage errorValue={touched.email && errors.email} />
<View style={styles.buttonContainer}>
<FormButton
buttonType="outline"
onPress={handleSubmit}
title="Send Email"
buttonColor="blue"
disabled={!isValid || isSubmitting}
/>
</View>
<ErrorMessage errorValue={errors.general} />
</Fragment>
)}
</Formik>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
marginTop: 150,
},
text: {
color: "#333",
fontSize: 24,
marginLeft: 25,
},
buttonContainer: {
margin: 25,
},
emailiconview:{
justifyContent:'center',
alignItems:'center',
top:"30%"
},
instrview1:{
top:'40%',
justifyContent:'center',
alignSelf:'center'
}, instrview2:{
top:'45%',
justifyContent:'center',
alignSelf:'center'
},
emailinputview:{
top:'50%'
}
});
export default ForgotPasswordScreen;
Below is the store auth where I fetch API:
auth.js:
import Device from '../../model/Device';
import AsyncStorage from '#react-native-async-storage/async-storage'
export const FORGOTPASSWORD = 'FORGOTPASSWORD';
export const resetpassword=(email) =>{
console.log(email);
return async dispatch =>{
const response = await fetch(
'http://my_IPV4_Address:4000/reset-password-email',
{
method: 'POST',
header: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: email
})
}
);
const resData = await response.text();
console.log(resData);
dispatch({type:FORGOTPASSWORD});
};
}
After running this I am getting the below error in Expo:
Network request failed
It is taking email, but not hitting the api.
email is cpoornima.1987#gmail.com
Email id to API cpoornima.1987#gmail.com
I am getting below error in NodeJs:
email from api undefined
undefined
I have added
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
to the Info.plist. I am just checking in IOS Simulator attached to Expo App. How to get through this?
Below is the auth.js fetch API which is working good.As soon as I press Send Email button, an email is going to provided email id for reset password using real Iphone device.
auth.js:
import Device from '../../model/Device';
import AsyncStorage from '#react-native-async-storage/async-storage'
export const FORGOTPASSWORD = 'FORGOTPASSWORD';
export const resetpassword=(email) =>{
const formData = new FormData();
formData.append('email',email);
console.log('Email id to API '+email);
return async dispatch =>{
fetch('http://My_IPV4_Address:4000/reset-password-email',
{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body:JSON.stringify({
email: email,
}),
})
.then(res => res.text())
.then(
(signupresult) =>{
}).catch(err =>{
console.log(err);
})
dispatch({type:FORGOTPASSWORD});
};
}

CORS Error - Why do I have CORS issues when I require some libraries as multer or fs with nodejs and express?

I am working on an application that let the user send a document from its computer to the app server. Just to let you know, the main aim is to extract some text/json elements server side to send to a database.
The frontend is made with React.js, the backend with node.js.
When I try to send a pdf, I sometimes encounter CORS and preflight CORS errors if I require "multer" or "fs".
In the configuration below, I am able to send my POST request ONLY if const multer=require("multer") is quoted (//). If I try to require multer I receive the following errors :
[XHR] OPTIONS https://api.mysite.fr/gettextfrompdf CORS Missing Allow
Origin
Blocage d’une requête multiorigines (Cross-Origin Request) : la
politique « Same Origin » ne permet pas de consulter la ressource
distante située sur https://api.mysite.fr/gettextfrompdf. Raison :
l’en-tête CORS « Access-Control-Allow-Origin » est manquant. Code
d’état : 500.
Here is my frontend :
import React from "react";
import { useState, useEffect } from "react";
function MyApp() {
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
const [rdyToSend, setRdyToSend] = useState(false);
const [selectedFile, setSelectedFile] = useState();
const [isFilePicked, setIsFilePicked] = useState(false);
const [isSelected, setIsSelected] = useState(false);
const changeHandler = (event) => {
console.log(event.target.files[0]);
setSelectedFile(event.target.files[0]);
setIsSelected(true);
};
const handleRdyToSend = () => {
console.log(selectedFile);
let formData = new FormData();
formData.append("fileToUpload", selectedFile, "sample.pdf");
for (var key of formData.entries()) {
console.log(key[0] + ", " + key[1]);
}
console.log(formData);
const requestOptions = {
method: "POST",
headers:
"https://xxxxxxxxxxxxxxxxxxxxx.com",
origin:
"https://xxxxxxxxxxxxxxxxxxxxx.com",
body: JSON.stringify({
fileToUpload: formData,
}),
headers: {
mode: "cors",
origin:
"https://xxxxxxxxxxxxxxxxxxxxx.com",
},
};
fetch("https://api.mysite.fr/gettextfrompdf", requestOptions)
.then((res) => res.json())
.then(
(result) => {
setIsLoaded(true);
setItems(result);
console.log(result);
},
(error) => {
setIsLoaded(true);
setError(error);
console.log(error);
}
);
setRdyToSend(true);
};
if (!rdyToSend) {
//form
return (
<div className="submitForm">
<form>
<label>
Déposer ici votre document PDF :
<input type="file" name="fileToUpload" onChange={changeHandler} />
{isSelected ? (
<div>
<p>Filename: {selectedFile.name}</p>
<p>Filetype: {selectedFile.type}</p>
<p>Size in bytes: {selectedFile.size}</p>
</div>
) : (
<p> Please select a file !</p>
)}
</label>
<input type="button" value="Envoyer" onClick={handleRdyToSend} />
</form>
</div>
);
} else {
if (error) {
return <div>Erreur : {error.message}</div>;
} else if (!isLoaded) {
return <div>Chargement...</div>;
} else {
console.log(items);
return (
<div>
Request done !<div>Texte : {items.text}</div>
<div>{items.sentFromClient}</div> */}
</div>
);
}
}
}
And there is my backend :
const express = require("express");
const app = express();
const multer = require("multer"); //This is the lib that causes my CORS errors
const normalizePort = (val) => {
const port = parseInt(val, 10);
if (isNaN(port)) {
return val;
}
if (port >= 0) {
return port;
}
return false;
};
const port = normalizePort(process.env.PORT || 4200);
const path = require("path");
var cors = require("cors");
app.options("*", cors());
app.use(cors());
app.use((req, res, next) => {
const allowedOrigins = [
"origin1",
"origin2",
"etc..."
];
const original = req.headers.origin;
if (allowedOrigins.includes(original)) {
res.setHeader("Access-Control-Allow-Origin", original);
cors({
origin: original,
credentials: true,
});
}
res.setHeader("Access-Control-Allow-Credentials", true);
// res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Headers", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, PATCH, OPTIONS"
);
next();
});
app.use(
express.urlencoded({
extended: true,
})
);
app.use(express.json({ type: "*/*" }));
app.post("/gettextfrompdf", function (req, res) {
//Here I send a response from server that I receive when multer is quoted...
});
I also have that situation if I require("fs").
I also tried to Enables preflight CORS according to this https://expressjs.com/en/resources/middleware/cors.html
Any help would be great, thanks !

React and Express iTunes Search API :: Error: Request failed with status code 404

I am currently creating an iTunes search application using an API and am stuck attempting to fetch the data to put together the result component.
Amongst other resources, I have been referring to the following information:
iTunes Search API
Please see below my code:
Backend - controllers - index.js
// Requiring Express.
const express = require("express");
// Requiring fetch from Node Fetch.
const fetch = require("node-fetch");
exports.getController =
("/search",
(req, res) => {
fetch(
`https://itunes.apple.com/search?term=${req.query.name}&limit=30&media=${req.query.type}`
)
.then((res) => res.json())
.then((results) => {
res.send(results);
});
});
Backend - routes - index.js
// Requiring Express.
const express = require("express");
// Requiring Router from Express.
const router = express.Router();
// Requiring controllers from the controllers folder's index.js.
const { getController } = require("../controllers/index.js");
router.get("/search", getController);
// Exporting controllers to server.js.
module.exports = router;
Backend - server.js
// Requiring Express.
const express = require("express");
// Requiring Morgan.
const morgan = require("morgan");
// Requiring CORS.
const cors = require("cors");
// Initializing express with variable "app".
const app = express();
// Requiring the routes index.js file.
const routes = require("./routes/index.js");
// Requiring Helmet.
const helmet = require("helmet");
/**
* Enabling App usages.
*/
const bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.json());
app.use(morgan("start"));
app.use(cors());
app.use(helmet());
app.use("/", routes);
const path = require("path");
if (process.env.NODE_ENV === "production") {
app.use(express.static("frontend/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "frontend", "build", "index.html"));
});
}
const PORT = process.env.PORT || 8080;
app.listen(PORT);
console.log(
"Navigate to http://localhost:8080/search. Server is listening on port",
PORT
);
app.use(function (err, req, res, next) {
console.log(err.stack);
res.status(500).send("Something broke!");
});
Frontend - search.js
// Imported react libraries and hooks.
import React, { useState, useEffect } from "react";
import axios from "axios";
// Imported Link from React Router Dom.
import { Link } from "react-router-dom";
// Imported components from React Bootstrap.
import { Row, Dropdown, ButtonGroup, Button } from "react-bootstrap";
// Imported icons from FontAwesome.
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faSearch } from "#fortawesome/free-solid-svg-icons";
// Imported components.
import Results from "./results.js";
const Search = () => {
const [name, setName] = useState("");
const [type, setType] = useState("");
const [results, setResults] = useState([]);
const [favourites, setFavourites] = useState([]);
const addToFav = (fav) => {
setFavourites([...favourites, fav]);
};
useEffect(() => {
localStorage.setItem("Favourites", JSON.stringify(favourites));
}, [favourites]);
const submitSearch = (e) => {
e.preventDefault();
axios
.get(`/search/${name}/${type}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
const queryAdded = res.data.results;
setResults(queryAdded ? queryAdded : []);
})
.catch((err) => {
console.log(err);
});
};
let nameEntry = "";
const nameSubmit = (e) => {
const entry = e.target.value;
nameEntry = entry;
setName(nameEntry);
};
const categories = [
{ name: "MUSIC", value: "music" },
{ name: "MUSIC VIDEO", value: "musicVideo" },
{ name: "APPS", value: "software" },
{ name: "EBOOK", value: "ebook" },
{ name: "AUDIO BOOK", value: "audiobook" },
{ name: "PODCAST", value: "podcast" },
{ name: "MOVIES", value: "movie" },
{ name: "TV SHOW", value: "tvShow" },
{ name: "SHORT FILM", value: "shortFilm" },
];
return (
<div id="searchcontainer">
<div id="searchcontent">
<div id="searchinput">
<input
type="text"
placeholder="Search..."
name="name"
onChange={nameSubmit}
/>
<Link to={`/search`}>
<button id="searchbutton" type="submit" onClick={submitSearch}>
<FontAwesomeIcon icon={faSearch} title="Search" />
</button>
</Link>
</div>
<Dropdown as={ButtonGroup}>
<Button variant="info" size="sm">
CATEGORIES
</Button>
<Dropdown.Toggle
split
variant="info"
id="dropdown-split-basic"
drop="bottom"
/>
<Dropdown.Menu>
{categories.map((category, i) => (
<Dropdown.Item
as="button"
key={i}
id="searchcategories"
value={category.value}
checked={type === category.value}
onChange={(e) => setType(e.currentTarget.value)}
>
{category.name}
</Dropdown.Item>
))}
</Dropdown.Menu>
</Dropdown>
</div>
<div className="search-page">
<div className="container-fluid">
<Row md={5}>
{results.length !== 0 ? (
results.map((content) => (
<Results addToFav={addToFav} content={content} />
))
) : (
<h1></h1>
)}
</Row>
</div>
</div>
</div>
);
};
// Exported search.js to landing.js.
export default Search;
Unfortunately I am getting the following error:
I have tried a couple of things, but nothing seems to be working. In fact, I think I might be over-complicating the code with all of my fiddling.
I would appreciate any help that anyone is willing to offer.
There are a few problems :
Currently, you're sending requests to the address of React app (http://localhost:3000). You need to send the request to the NodeJS application instead.
axios
.get(`http://localhost:8080/search/${name}/${type}`, { // add the address of NodeJS application
If you want to send data like this /search/${name}/${type}, then in the backend, req.query won't work. You should use req.params and change your route accordingly. Read the Express document here. Or, you need to change the URL in the frontend part to /search/?name={name}&type=${type}
Finally, in the log, the URL is http://localhost:3000/search/korn. There is 1 missing parameter, which can give you a bad URL in your backend app.
https://itunes.apple.com/search?term=${req.query.name}&limit=30&media=${req.query.type} may result https://itunes.apple.com/search?term=korn&limit=30&media=undefined
You need a mechanism to deal with missing data.

Cannot fetch between Express and React apps due to CORS

My app was working fine and I was able to fetch data between my Express and React servers. I reorganised my code and now i cannot get rid of the CORS errors and cannot fetch any data at all. I cannot move on with my project and simply can't figure it out for myself, I have really tried.
The front end works ok until i try to login, and then the authentication fails
I have tried adding headers and have installed CORS to my express app. I have a proxy specified in my react package.json to the express URL.
This is my Express server.js
const express = require('express');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const path = require('path');
const cors = require('cors');
const methodOverride = require('method-override');
const db = require('./db/index.js')
db.on('error', console.error.bind(console, 'MongoDB connection error:'))
require('dotenv').config();
const app = express();
app.disable('x-powered-by');
app.use(function(req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);
// Pass to next layer of middleware
next();
});
app.use(methodOverride('_method'));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(cors({
origin: 'http://localhost:8080'
}));
app.use(express.static(path.join(__dirname, '../build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '../build', 'index.html'));
});
const userRouter = require('./routes/user-routes')
app.use('/api', userRouter)
const fileRouter = require('./routes/file-routes')
app.use('/file', fileRouter)
// mongoose.connection.once('open', run);
app.listen(process.env.PORT || 8080);
console.log('Server is listening on port ' + process.env.PORT);
This is my user controller
const User = require('../models/Users');
const secretShh = 'mysecretsshhh';
const jwt = require('jsonwebtoken');
const home = (req, res) => {
res.send('Welcome!');
};
const secret = (req, res) => {
res.send('The password is potato');
};
const register = (req, res) => {
const { email, password } = req.body;
const user = new User({ email, password });
user.save(function(err) {
if (err) {
console.log(err);
res.status(500).send("Error registering new user please try again.");
} else {
res.status(200).send("Welcome to the club!");
}
});
};
const authenticate = (req, res) => {
const { email, password } = req.body;
User.findOne({ email }, function(err, user) {
if (err) {
console.error(err);
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (!user) {
res.status(401)
.json({
error: 'Incorrect email or password'
});
} else {
user.isCorrectPassword(password, function(err, same) {
if (err) {
res.status(500)
.json({
error: 'Internal error please try again'
});
} else if (!same) {
res.status(401)
.json({
error: 'Incorrect email or password'
});
} else {
// Issue token
const payload = { email };
const token = jwt.sign(payload, secretShh, {
expiresIn: '1h'
});
res.cookie('token', token, { httpOnly: true }).sendStatus(200);
}
});
}
});
};
const token = (req, res) => {
res.sendStatus(200);
};
module.exports = {
home,
secret,
register,
authenticate,
token
}
this is my user routes
const express = require('express')
const UserCtrl = require('../controllers/user-ctrl')
const withAuth = require('../middleware');
const router = express.Router()
router.get('/home', UserCtrl.home)
router.get('/secret', withAuth, UserCtrl.secret)
router.post('/register', UserCtrl.register)
router.post('/authenticate', UserCtrl.authenticate)
router.get('/checktoken', withAuth, UserCtrl.token)
module.exports = router
this is a middleware function to check tokens, this is where the error seems to point towards, but I'm sure its actually something to do with the proxy and fetch being blocked by CORS.
const jwt = require('jsonwebtoken');
const secret = 'mysecretsshhh';
const withAuth = (req, res, next) => {
const token =
req.body.token ||
req.query.token ||
req.headers['x-access-token'] ||
req.cookies.token;
if (!token) {
res.status(401).send('Unauthorized: No token provided');
} else {
jwt.verify(token, secret, function(err, decoded) {
if (err) {
res.status(401).send('Unauthorized: Invalid token');
} else {
req.email = decoded.email;
next();
}
});
}
}
module.exports = withAuth;
this is my auth components where the error is also pointing towards
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom';
//withAuth is a high-order component which takes in a component to protect
export default function withAuth(ComponentToProtect) {
return class extends Component {
constructor() {
super();
this.state = {
loading: true,
redirect: false,
};
}
async componentDidMount() {
fetch('http://localhost:8080/api/checktoken', {
credentials: 'include',
mode: 'cors'
})
.then(res => {
if (res.status === 200) {
this.setState({ loading: false });
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
this.setState({ loading: false, redirect: true });
});
}
render() {
const { loading, redirect } = this.state;
if (loading) {
return null;
}
if (redirect) {
return <Redirect to="/login" />;
}
return (
<React.Fragment>
<ComponentToProtect {...this.props} />
</React.Fragment>
);
}
}
}
login component
import React, { Component } from 'react';
export default class Login extends Component { //impplicit vs explicit returns
constructor(props) {
super(props)
this.state = {
email : '',
password: ''
};
}
handleInputChange = (event) => {
const { value, name } = event.target;
this.setState({
[name]: value
});
}
onSubmit = async (event) => {
event.preventDefault();
fetch('/api/authenticate', {
method: 'POST',
body: JSON.stringify(this.state),
headers: {
'Content-Type': 'application/json'
}
})
.then(res => {
if (res.status === 200) {
this.props.history.push('/');
} else {
const error = new Error(res.error);
throw error;
}
})
.catch(err => {
console.error(err);
alert('Error logging in please try again');
});
}
render() {
return (
<form onSubmit={this.onSubmit}>
<h1>Login Below!</h1>
<input
type="email"
name="email"
placeholder="Enter email"
value={this.state.username}
onChange={this.handleInputChange}
required
/>
<input
type="password"
name="password"
placeholder="Enter password"
value={this.state.password}
onChange={this.handleInputChange}
required
/>
<input type="submit" value="Submit"/>
</form>
);
}
}
This is the main error:
Access to fetch at 'http://localhost:8080/api/checktoken' from origin 'http://localhost:3000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8080' that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
It also says:
withAuth.jsx:17 GET http://localhost:8080/api/checktoken net::ERR_ABORTED 401 (Unauthorized)
In my express app the terminal says it cant read the token in the middleware, I presume its also due to cors :
TypeError: Cannot read property 'token' of undefined
at withAuth (/Users/nancycollins/virtuload-beta/backend/middleware.js:6:16)
Apologies if this is too much information I've just been stuck on this for too long and really dont know what else to do.
Update:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
With:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
I encourage you to do app.use(cors()); before those lines
app.disable('x-powered-by');
app.use(function(req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
...
Express stacks those functions lets say as a "array" and because of that the order matters
Hope it resolve your problem.
Bit late to the party but just going to leave my answer here incase someone else has the same problem.
The idea is to allow CORS request to your Express server. Go to the directory with your server.js file and run:
npm install cors
Then inside server.js add the following lines:
const cors = require('cors');
app.use(cors());

Resources