Getting a cors error running vue with express - node.js

I'm running my Vue App on my express server (nodejs running on port 60702) like:
'use strict';
const fs = require('fs');
const path = require('path');
const express = require('express');
var https = require('https');
const morgan = require('morgan');
const cors = require('cors');
const bodyParser = require('body-parser');
const nconf = require('./config');
const pkg = require('./package.json');
const swaggerSpec = require('./swagger');
const swaggerUI = require('swagger-ui-express');
const app = express();
app.options('*', cors()) // include before other routes
// create a write stream (in append mode)
var accessLogStream = fs.createWriteStream(path.join(__dirname, 'access.log'), {
flags: 'a'
});
// setup the logger
app.use(morgan('combined', {
stream: accessLogStream
}));
// Enable CORS (cross origin resource sharing)
app.use(cors());
// Set up body parser
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
// Load the Vue App
app.use(express.static(path.join(__dirname, '../../client/pvapp-client/dist')));
app.get('/api/version', (req, res) => res.status(200).send(pkg.version));
const userRouter = require('./routes/user');
const systemRouter = require('./routes/system');
const yieldRouter = require('./routes/yield');
const adjustmentRouter = require('./routes/adjustmentfactors');
app.use('/user', userRouter);
app.use('/system', systemRouter);
app.use('/yield', yieldRouter);
app.use('/adjustmentfactors', adjustmentRouter);
//Default route
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, '../../client/pvapp-client/dist/index.html'));
});
//const listener = app.listen(nconf.get('port'), () => console.log(`Ready on port ${listener.address().port}.`));
https.createServer({
key: fs.readFileSync('certs/apache-selfsigned.key'),
cert: fs.readFileSync('certs/apache-selfsigned.crt')
}, app)
.listen(nconf.get('port'), function() {
console.log(`App listening on port ${nconf.get('port')}! Go to https://192.168.51.47:${nconf.get('port')}/`)
});
The User router is:
router.post('/login', async (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods', 'GET,POST");
let compareUser = await db.query('SELECT * FROM app_users WHERE username=? LIMIT 1', [req.body.username]); // use db.query() to retrieve the password
if (compareUser.length < 1) // compareUser is an array with at most one item
res.sendStatus(403);
let valid = bcrypt.compareSync(req.body.password, compareUser[0].password);
if (!valid)
res.sendStatus(403);
let user = new User(compareUser[0]);
const token = jwt.sign({
user
}, nconf.get('jwtToken'), {
expiresIn: '14d'
});
Object.assign(user, {
token
});
res.json(user);
});
The vue config is:
module.exports = {
baseUrl: process.env.NODE_ENV === 'production' ? '/vue' : '/',
devServer: {
port: 60702,
https: true,
disableHostCheck: true
}
};
Axios:
const apiClient = axios.create({
baseURL: `https://192.168.51.47:60702`,
withCredentials: false, // This is the default
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
export default {
// user Endpoints
getUser(email) {
return apiClient.get(`/user/${email}`)
},
registerUser(user) {
return apiClient.post(`/user/register`, user)
},
loginUser(user) {
return apiClient.post(`/user/login`, user)
},
But even if I included cors I'm getting:
Cross-source (cross-origin) request blocked: The same source rule
prohibits reading the external resource on
https://143.93.46.35:60702/user/login. (Reason: CORS request failed).
The axios call in vue also has the correct baseUrl with the port.
I checked the POST request to the backend at /user/login with Postman and get the exprected correct request, too.

It was solved by re-creating the dist folder with
npm run build
Thanks to #Dan for his help
Don't use apiClient. Do a get with the full url, rebuild your app,
delete old dist folder, CTRL+F5 refresh once loaded. In fact, put a
"?" on the end of the url and make sure you see it in Chrome headers

Related

How can I communicate with Cloudfront and the ec2 node server?

using stack
Client: React, Redux, axios
Server: AWS-EC2, Route 53, S3, CloudFront, NodeJS, express
First, I bought a domain from route53.(ACM certificate issuance completed)
Second, I registered the build file in the bucket as a static website in S3.
Third, linked the Route 53 and S3 bucket to CloudFront.
Fourth, EC2 set ELB and EIP.
Fifth, ec2 contains node.js epxress server.
Sixth, CloudFront, Redirect from S3 (www.domain.link => domain.link)
was set to
The code of the problematic Client and Server is as follows.
Client.js
import axios from "axios";
import { TYPES, MAF } from "./types";
const API_AUTH = "https://www.domain.link/auth";
const API_USER = "https://www.domain.link";
//필수!!
axios.defaults.withCredentials = true;
export function loggedIn(data) {
return (dispatch) => {
axios.post(`${API_AUTH}/login`, data).then((res) => {
console.log(res);
dispatch({
type: TYPES.LOGIN_SUCCESS,
// payload: res.data.userData,
});
dispatch({
type: MAF.HIDE_MODAL,
});
});
};
}
export function register(data) {
return (dispatch) => {
axios.post(`${API_AUTH}/register`, data).then((res) => {
dispatch({
type: TYPES.REGISTER_SUCCESS,
payload: res.data,
});
});
};
}
server.js
./routes/user.js
const router = require("express").Router();
const {
login,
register,
logout,
profile,
} = require("../controller/userController/userController");
const { authorization } = require("../config/JWTConfig");
router.post("/auth/login", login);
router.post("/auth/register", register);
router.get("/auth/logout", authorization, logout);
router.get("/auth/profile", authorization, profile);
module.exports = router;
./app.js
const express = require("express");
// const passportConfig = require("./passport/index");
const passport = require("passport");
const http = require("http");
const https = require("https");
const path = require("path");
const fs = require("fs");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const logger = require("morgan");
require("dotenv").config();
const authRoute = require("./routes/users");
const mainRoute = require("./routes/main");
const port = process.env.PORT || 3000;
const app = express();
const whitelist = [
"http://localhost:3000",
"http://*.doamin.link",
"http://doamin.link",
"http://doamin.link/*",
];
const corsOption = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1 || !origin) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE", "OPTION"],
};
app.use(cookieParser());
app.use(logger("dev"));
app.use(cors(corsOption));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(mainRoute);
app.use(authRoute);
let server;
if (fs.existsSync("./cert/key.pem") && fs.existsSync("./cert/cert.pem")) {
const privateKey = fs.readFileSync(__dirname + "/cert/key.pem", "utf8");
const certificate = fs.readFileSync(__dirname + "/cert/cert.pem", "utf8");
const credentials = { key: privateKey, cert: certificate };
server = https.createServer(credentials, app);
server.listen(port, () => console.log("https server Running"));
} else {
server = app.listen(port, () => {
console.log(`http server Running`);
});
}
module.exports = server;
When I click the Postman or browser login button, this error occurs.
Access to XMLHttpRequest at 'https://www.domain.link/login'
from origin 'https://domain.link' 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.
createError.js:16 Uncaught (in promise) Error: Network Error
at e.exports (createError.js:16)
at XMLHttpRequest.p.onerror (xhr.js:84)
domain.link or www.domain.link or the above error occurs.
Postman
How do I get CloudFront + S3 to communicate with EC2?
in your browser or postman
www.domain.link
After connecting to domain.link
When you make a login button or post request
I hope it works well.
If something is missing, please let me know what is missing. I will add more.
You specify allowed methods for CloudFront in your cache behavior. By default only GET and HEAD are allowed:

express server returns 405 on routes in production

Im building an express instance for the first time and ive run into an issue where everything works locally, but when deployed sending a post request to the route responds:
Failed to load resource: the server responded with a status of 405
(Not Allowed)
Ive included the relevant code below:
server/index.js
const express = require('express');
const bodyParser = require('body-parser')
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
const routes = require('./routes')(express)
require('./db')
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(process.env.PORT || 8080);
app.use('/', routes);
routes/index.js
var mongoose = require("mongoose");
const randomId = require('random-id');
const Submissions = require('../api/Submissions')
// routes/index.js
module.exports = (express) => {
// Create express Router
var router = express.Router();
// add routes
router.route('/submission')
.post((req, res) => {
let newSubmission = new Submissions(req.body);
newSubmission._id = randomId(17, 'aA0');
// Save the new model instance, passing a callback
newSubmission.save(function(err,response) {
if (err) {
console.log(err)
} else {
res.setHeader('Content-Type', 'application/json');
res.json({'success':true})
}
// saved!
})
});
return router;
}
client.js
let submission = {
name: this.state.newSubmission.name.trim(),
body: this.state.newSubmission.body.trim(),
email: this.state.newSubmission.email.trim(),
};
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(submission),
};
fetch("/submission", requestOptions)
.then((response) =>
response.json().then((data) => ({
data: data,
status: response.status,
}))
)
.then((res) => {
if (!res.data.success) {
notifier.warning('Failed to submit');
} else {
notifier.success('Submission successful');
}
});

Can Not POST NodeJS Express

I was trying to make an axios post request to an express server and I receive that Error: Request failed with status code 404 at createError. Postman says Can Not POST. I don't know what could be wrong, i'm new in all this, so all the help it's good, thanks.
Axios and Express server are from 2 different link. They are google cloud function.
Thanks for the help
Axios Post Request :
exports.notification = (req, res) => {
var axios = require('axios');
var https = require('https');
var bodyParser = require('body-parser');
var config = {
headers: {
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Type' : 'text/html',
'Content-Type' : 'application/json' }
};
var info = {
ids:[req.body.id,req.body.id1],
type: req.body.type,
event: req.body.action,
subscription_id: req.body.subid,
secret_field_1:null,
secret_field_2:null,
updated_attributes:{
field_name:[req.body.oname,req.body.nname]}
};
var myJSON = JSON.stringify(info);
return axios.post('https://us-central1-copper-mock.cloudfunctions.net/api/notification-example', myJSON)
.then((result) => {
console.log("DONE",result);
})
.catch((err) => {
console.log("ERROR",err);
console.log("Error response:");
console.log(err.response.data);
console.log(err.response.status);
console.log(err.response.headers);
})
};
Express Server
const express = require ('express');
const https = require ('https');
const bodyParser = require ('body-parser');
const app = express();
const port = 8080;
// ROUTES
var router = express.Router(); // get an instance of router
router.use(function(req, res, next) { // route middleware that will happen on every request
console.log(req.method, req.url); // log each request to the console
next(); // continue doing what we were doing and go to the route
});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use('/',require ('./Routers/API/home'));
app.use('/leads',require ('./Routers/API/leads'));
app.use('/people',require ('./Routers/API/people'));
app.use('/companies',require ('./Routers/API/companies'));
app.use('/opportunities',require ('./Routers/API/opportunities'));
app.use('/projects',require ('./Routers/API/projects'));
app.use('/tasks',require ('./Routers/API/tasks'));
app.use('/activities',require ('./Routers/API/activities'));
app.use('/notification-example',require ('./Routers/API/notification_example'));
app.use('/', router); // apply the routes to our application
// START THE SERVER
// ==============================================
app.listen(port);
console.log('Listening ' + port);
module.exports={
app
};
Notification Route
const express = require('express');
const router = express.Router();
//const notification_example = require('../../Notification');
router.get('/', function(req, res) {
console.log('DATA',JSON.parse(res.data));
console.log('BODY',JSON.parse(res.body));
});
module.exports = router;

Passport Facebook-Login is failing with 401 error in node and react app

I get the following error when I try to authenticate with passport. I wonder if I am missing some middleware or something. What ever the case, this just is not working at the moment. I am getting the following error on the backend:
] { message: 'You should provide access_token' }
[0] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
App.js:29 POST http://127.0.0.1:3000/api/users/auth/facebook 401 (Unauthorized)
I have made sure that the access token prints on the frontend:
this is ther token blob {"access_token":"EAAGTZAFMSr8YBACcmZAaEaEMTbCKICwJqiohySMxb1pPrJaaECiPqfOqiPFln4hp2pucvSm9Pr42twDQVZBt4KZAIoEENaAINHVBcfZB8YdRM23Y9VjDSeSnUtOsyynufjCBdQyNozpI2N4bTJotZAEmLETjIqLZBxwP9VxBdDFZAYWMofEiZCUDrQwGk7fBahs8SEtzTB80kfAZDZD"}
Here is the frontend
facebookResponse = (response) => {
const token= JSON.stringify({access_token: response.accessToken}, {type : 'application/json'});
console.log('this is ther token blob', token);
const options = {
method: 'POST',
body: token,
mode: 'cors',
cache: 'default'
};
fetch('api/users/auth/facebook', options).then(r => {
const token = r.headers.get('x-auth-token');
if(token){
try {
r.json().then(user => {
if (token) {
this.setState({isAuthenticated: true, user, token})
}
});
} catch{
console.log('error');
}
}
})
};
Here is the backend
var express = require('express');
var router = express.Router();
var { generateToken, sendToken } = require('./token.utils');
var passport = require('passport');
var config = require('./config');
var request = require('request');
require('../../passport')();
router.use(passport.initialize());
router.use(passport.session());
router.post('/auth/facebook',
function(req, res, next){
passport.authenticate('facebook-token', function(error, user, info){
console.log(error);
console.log(user);
console.log(info);
if (error) {
res.status(401).send(error);
} else if (!user) {
res.status(401).send(info);
} else {
next();
}
res.status(401).send(info);
})(req, res);
});
module.exports = router;
Here is my jwt strategy I am using facebook login:
require('./mongoose')();
var passport = require('passport');
var User = require('mongoose').model('User');
var FacebookTokenStrategy = require('passport-facebook-token');
module.exports = function () {
passport.use(new FacebookTokenStrategy({
clientID: '443534076456---',
clientSecret: 'd9c12cd1c8c7fcea7abb391a0bbb---'
},
function (accessToken, refreshToken, profile, done) {
User.upsertFbUser(accessToken, refreshToken, profile, function(err, user) {
return done(err, user);
});
}));
};
Here is the main server file:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const passport = require('passport');
const path = require('path');
const users = require('./routes/api/users');
const cors = require('cors');
const app = express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
var corsOption = {
origin: true,
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
credentials: true,
exposedHeaders: ['x-auth-token']
};
app.use(cors());
// const db = require('./config/keys').mongoURI;
// mongoose.connect("mongodb://user1:Voodoo12#ds263146.mlab.com:63146/fb-login-chat").then(()=> console.log('MongoDb Connected'))
// .catch(err=> console.log(err));
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
app.use('/api/users', users);
//serve static assets if in production
// if(process.env.NODE_ENV === 'production'){
// //Set a static folder
// app.use(express.static('client/build'))
// app.get('*', (req, res)=>{
// res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
// });
// }
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server running on port ${port}`));
I thinks your API is not able to decode the payload and extract your access token
try to add headers in yours options for the request
const options = {
method: 'POST',
body: token,
mode: 'cors',
cache: 'default',
// add headers
headers: { 'Content-type': 'application/json' }
};
Regards,
MA

increase express post body limit to proxied api

I have a seperate frontend and backend, where all requests to http://frontend.com/api are proxied to the backend. However we allow image uploads to be 10mb max, which gets limited by the 1mb internal limit of express on all request bodies.
I have the following config:
const express = require('express');
const consola = require('consola');
const { Nuxt, Builder } = require('nuxt');
const helmet = require('helmet');
// Express
const app = express();
const host = process.env.HOST || '127.0.0.1';
const port = process.env.PORT || 8080;
app.set('port', port);
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js');
config.dev = !(process.env.NODE_ENV === 'production');
async function start() {
// Init Nuxt.js
const nuxt = new Nuxt(config);
if (config.dev) {
const builder = new Builder(nuxt);
await builder.build();
}
// NOTE: Only in production mode
if (!config.dev) {
// Helmet default security + Referrer + Features
app.use(helmet());
}
// Proxy /api to proper backend
app.use('/api', proxy(process.env.API_ENDPOINT || 'http://localhost:3000'));
// Give nuxt middleware to express
app.use(nuxt.render);
// Listen the server
app.listen(port, host);
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true,
});
}
start();
I have tried adding body-parser, until I found out this only works for non multipart/form type of requests. Considering that this isn't an express backend, but only used to serve SSR (with nuxt), I have no idea how to get this to work with something like multer or busboy.
Can this be done without having to setup nginx as a reverse proxy?
Express itself doesn't impose any limits on body size, because it doesn't process the request body at all.
However, some middleware do impose a limit, like body-parser and express-http-proxy, which is what you're using.
To increase the limit to 10MB:
app.use('/api', proxy(process.env.API_ENDPOINT || 'http://localhost:3000', {
limit: '10mb'
));
The way mine works is I define my api base url in a config file which I reference in an api/init.js file. This file is added to plugins in nuxt.config.js. This is that file:
import axios from 'axios'
import {baseURL} from '~/config'
import cookies from 'js-cookie'
import {setAuthToken, resetAuthToken} from '~/utils/auth'
import { setUser, setCart } from '../utils/auth'
axios.defaults.baseURL = baseURL
const token = cookies.get('x-access-token')
const currentUser = cookies.get('userDetails')
const currentCart = cookies.get('userCart')
if (token) {
setAuthToken(token)
setUser(currentUser)
setCart(currentCart)
} else {
resetAuthToken()
}
The backend runs on it's own server which I launch with node index.js and it is the base url that my init.js looks for. The backend index.js looks like this:
const mysql = require('mysql')
const express = require('express')
const bodyParser = require('body-parser')
const config = require('./config')
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const multer = require('multer')
const auth = require('./auth')
const files = require('./files')
const create = require('./create')
const get = require('./get')
const delet = require('./delet')
const blogFiles = require('./blogFiles')
const db = mysql.createConnection(config.db)
const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS')
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, x-access-token, userDetails, userCart')
if (req.method === 'OPTIONS') {
res.sendStatus(200)
}
else {
next()
}
})
app.use((err, req, res, next) => {
if (err.code === 'LIMIT_FILE_TYPES') {
res.status(422).json({ error: 'Only images are allowed'})
return
}
if (err.code === 'LIMIT_FILE_SIZE') {
res.status(422).json({ error: `Too Large. Max filesize is ${MAX_SIZE/1000}kb` })
return
}
})
app.use('/auth', auth({db, express, bcrypt, jwt, jwtToken: config.jwtToken}))
app.use('/files', files({db, express, multer}))
app.use('/blogFiles', blogFiles({db, express, multer}))
app.use('/create', create({db, express}))
app.use('/get', get({db, express}))
app.use('/delet', delet({db, express}))
app.get('/test', (req, res) => {
db.query('select 1+1', (error, results) => {
if (error) {
return res.status(500).json({type: 'error', error})
}
res.json({type: 'success', message: 'Test OK', results})
})
})
app.listen(config.port)
console.log('App is running on port ' + config.port)
The files.js handles file uploads and as you can see index.js requires that. It is in there that I use multer to handle the upload limit and such. This is file.js
module.exports = ({db, express, multer }) => {
const routes = express.Router()
const fileFilter = function(req, file, cb) {
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
if (!allowedTypes.includes(file.mimetype)) {
const error = new Error('Wrong file type')
error.code = 'LIMIT_FILE_TYPES'
return cb(error, false)
}
cb(null, true)
}
const MAX_SIZE = 250000
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../frontend/assets/images')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
const upload = multer ({
storage: storage,
fileFilter,
limits: {
fileSize: MAX_SIZE
},
})
routes.post('/upload', upload.single('file'), (req, res) => {
res.json({ file: req.file })
})
return routes
}
As you can see I set the MAX_SIZE for my file uploads here so guess you can set any limit and as multer is handling it, it will over ride any limits set by express.

Resources