I wanted to give a post request to the required URL but without proxy setting it was giving cors error, I have gone through and end up with setting the proxy but still it is taking the localhost as the URL. I have attached my proxyfile.js and my code snippet with the error below.
export function PostData(userData) {
var targetUrl = "/downloadableReport";
return new Promise((resolve, reject) => {
fetch(targetUrl, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
Accept: "application/json"
},
body: JSON.stringify({
requestData: {
userName: userData.userName,
password: userData.password
}
})
}).then(response => response.json());
});
}
This is the setupProxy.js code:
const proxy = require("http-proxy-middleware");
module.exports = function(app) {
app.use(
proxy("/downloadableReport", {
target: "http://192.168.1.220:28080/xms/abc",
changeOrigin: true
})
);
};
And this is the error:
If CORS is the problem and you are using express as the backend server,
then
var allowCrossDomain = function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With, Role');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.sendStatus(200);
} else {
next();
}
};
and then add
app.use(allowCrossDomain);
Ditch the proxy. To me, your problem looks like, you're POSTing data to the React App itself. If you are indeed having both the API and React, in the same project, I would suggest that you split them.
If they are not indeed together, update the targetUrl to a proper url with the protocol and the domain. Like var targetURl = 'http://localhost:3000/downloadableReport.
UPDATE: I read your comment reply to Sudhir. Edit the target Url as the full path to the API var targetUrl = "http://192.168.1.220:28080/xmsreport/report/downloadableReport" and add the CORS code I have provided above to the API at 192.168.1.220:28080
Related
I have the following headers setup in my node js api app:
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested, Content-Type, Accept Authorization"
);
if (req.method === "OPTIONS") {
res.header(
"Access-Control-Allow-Methods",
"POST, PUT, PATCH, GET, DELETE"
);
return res.status(200).json({});
}
next();
});
With this config I can send GET, POST request to my api hosted in heroku from Postman.
But when I try from my frontend app built with vue. I get the following error.
And I'm using fetch to send the request to remote api:
async signup() {
try {
const formData = new FormData();
formData.firstName = this.firstName;
formData.lastName = this.lastName;
formData.email = this.email;
formData.password = this.password;
formData.confirmPassword = this.password;
formData.mobile = this.mobile;
formData.gender = this.gender;
formData.profileImg = this.profileImg;
const response = await fetch(
"https://api-url.com/auth/patient/signup",
{
body: formData,
method: "POST",
}
);
const data = await response.json();
this.response = JSON.stringify(data);
} catch (error) {
console.log(error);
}
}
Can anyone point the mistakes I've made here ?
I think you need to set the headers in the fetch call. I see that you have already added body and method.
headers: { 'Content-Type': 'application/json' }
I'm getting a TypeError: Failed to fetch error when I attempt to send a post request using fetch on the front-end and an express route on the back-end.
I'm able to successfully create the new user in the db, but when attempting to obtain that new user data through the fetch promise, that's when the error is being thrown.
app.js
function createNewUser() {
let formUsername = document.getElementById('signup-username').value;
let formEmail = document.getElementById('signup-email').value;
let formPassword = document.getElementById('signup-password').value;
let url = "/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: 'same-origin', // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow', // manual, *follow, error
referrer: 'no-referrer',
body: JSON.stringify(newUserData),
}).then(res => res.json())
.then(response => console.log('Success: ', JSON.stringify(response)))
.catch(error => console.error('Error: ', error));
}
users.js
router.post('/users', function(req, res) {
User.create(req.body)
.then(function(user) {
res.json({
user: user
})
}
});
server.js
const express = require('express');
const app = express();
const fs = require('fs');
const path = require('path');
const bodyParser = require('body-parser');
const bcrypt = require('bcryptjs');
const auth = require('./auth');
const router = require('./routes/routes.js');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(router);
app.use('/', express.static(path.join(__dirname, 'public')));
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE" // what matters here is that OPTIONS is present
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization", "Access-Control-Allow-Origin");
next();
});
app.listen(3000, function(){
console.log("Listening on port 3000");
});
I need to get that user object back in order to access its data.
Edit:
So, I've figured out that the issue has to do with how the request is submitted on the front-end. If I create the following function and then call it when app.js is loaded, then everything works:
function createNewUserTest() {
let formUsername = 'dd';
let formEmail = 'd#d.com';
let formPassword = 'secrete';
let url = "/api/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUserData),
})
.then(res => res.json())
.then(response => console.log('Success: ', response))
.catch(error => console.error('Error: ', error));
}
createNewUserTest();
But, if I try to call this function either through onsubmit in the form or onclick on the button in the html, or if I use an event listener (see below, which is in app.js), then I get the TypeError: Failed to fetch error:
let signupSubmitButton = document.getElementById('signup-submit');
signupSubmitButton.addEventListener('click', createNewUserTest);
This is even more baffling to me. I'm required to use Vanilla JS and I need to create the user through a form submission, but not sure what I need to adjust here.
Solution
Foiled by the event.preventDefault() again. This was all I needed.
let signupForm = document.getElementById('signup-form');
signupForm.addEventListener('submit', function(event) {
event.preventDefault();
let formUsername = document.getElementById('signup-username').value;
let formEmail = document.getElementById('signup-email').value;
let formPassword = document.getElementById('signup-password').value;
let url = "/api/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUserData),
})
.then(res => res.json())
.then(response => console.log('Success: ', response))
.catch(error => console.error('Error: ', error));
});
The issue was that the page was reloading, which kept me from getting the data back in time. The solution was to simply add event.preventDefault() inside the listener.
app.js
let signupForm = document.getElementById('signup-form');
signupForm.addEventListener('submit', function(event) {
event.preventDefault();
let formUsername = document.getElementById('signup-username').value;
let formEmail = document.getElementById('signup-email').value;
let formPassword = document.getElementById('signup-password').value;
let url = "/api/users";
let newUserData = {
username: formUsername,
email: formEmail,
password: formPassword
}
fetch(url, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newUserData),
})
.then(res => res.json())
.then(response => console.log('Success: ', response))
.catch(error => console.error('Error: ', error));
});
The question is about "TypeError failed to fetch". The wording of the message sends one in the direction of network/server/CORS type issues as explored in other answers, but there is one cause I have discovered that is completely different.
I had this problem and took it at face value for some time, especially puzzled because it was provoked by my page POSTing in Chrome but not in Firefox.
It was only after I discovered chrome://net-internals/#events and saw that my request suffered from 'delegate_blocked_by = "Opening Files"' that I finally had a clue.
My request was POSTing a file uploaded from the user's computer via a file input element. This file happened to be a file open in Excel. Although it POSTed fine from Firefox, it was only when closed that it could be posted in Chrome.
Users of your web application need to be advised about this potential issue, and web developers should also be aware that "TypeError failed to fetch" can sometimes mean "TypeError didn't get as far as trying to fetch"
When it comes to CORS problems it's very often because the server doesn't know how to handle it properly. Basically every time you include a header like access-control-origin to your request it will instigate OPTIONS preflight request as well and if your server is not expecting that it will throw an error, because it was expecting a POST only requests.
In other words - try again without the "Access-Control-Origin": "*" part and see if it works or just try patching it on the server with something like this:
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE" // what matters here is that OPTIONS is present
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
I'm trying to send data from client's inputs based on React.js to server written in Node.js which put it to DB. I have no errors and after submit, new records show in database but they are empty. I have two inputs and I'm joining them in one string and trying send it to DB (so DB has one property). Can you check my code and see what is wrong? Maybe something with headers...
This is function in React component:
addCompetitor = event => {
event.preventDefault();
const name = this.state.draftCompetitorName;
const lastname = this.state.draftCompetitorLastname;
fetch(`http://localhost:5000/competitors`, {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ name: `${name}${lastname}` })
})
.then(response => response.json())
};
This is server POST response:
app.post("/competitors/", urlencodedParser, function (req, res) {
const newCompetitor = new Competitor({ name: req.body.name });
newCompetitor.save().then(competitor => res.json(competitor));
});
And it's app configuration:
app.use(function (req, res, next) {
res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, OPTIONS, PUT, PATCH, DELETE"
);
res.setHeader(
"Access-Control-Allow-Headers",
"Content-Type",
"X-Requested-With"
);
res.setHeader("Access-Control-Allow-Credentials", true);
next();
});
If not first install bodyparser. This parses incoming request bodies in a middleware before your handlers, which will be available under the req.body property.
app.use(bodyParser.json({
limit: '50mb',
parameterLimit: 100000
}))
Alternatively what is the express version you are using ? Is it greater than 4.16? Then you can also use
app.use(express.json());
See notes here
https://expressjs.com/en/api.html#express.json
Modify your code
let databody = {
"name": `${name}${lastname}`,
"otherprop": this.state.otherprop
}
From frontend use
body: JSON.stringify(databody),
In express end remove urlencodedParser , should be like below:
app.post("/competitors", function (req, res) {
console.log(req.body);
});
You are using urlencodedParser as a middleware so I guess you used bodyParser.urlencoded({}) but your request is sending a json format. Try adjusting your request by adding the following header:
'Content-Type': 'application/x-www-form-urlencoded'
EDIT:
Also body should be in the following format:
body: `name=${name}${lastname}`
I'm trying to send some data to Node using React. Here's my React code:
sendMail(e) {
e.preventDefault();
// fetch('/https://uczsieapp-mailer.herokuapp.com/', {
var name = document.getElementById('name').value;
var contactReason = document.getElementById('contactReason').value;
var email = document.getElementById('email').value;
var additionalInfo = document.getElementById('additionalInfo').value;
var body = {
name: name,
contactReason: contactReason,
email: email,
additionalInfo: additionalInfo,
};
body = JSON.stringify(body);
console.log(body);
fetch('http://localhost:4000/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
content: body,
}).then(r => console.log(r)).catch(e => console.log(e));
}
Here's my Node code:
var cors = require('cors');
var app = express();
app.use(cors());
var a = '=';
router.post('/', (req, res, next) => {
console.log('mailing');
console.log(a);
a += '=';
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com", // hostname
auth: {
user: 'someuser#gmail.com',
pass: 'testgmail'
}
});
console.log(req.body.content);
let mailOptions = {
from: `${req.body.name} ${req.body.email}`, // sender address
to: 'alexander.ironside#mygeorgian.ca', // list of receivers
subject: 'Email from UczSieApp contact form', // Subject line
text: 'Hello world ', // plaintext body
html: `
<h4>Imie: ${req.body.name}</h4>
<h4>Email: ${req.body.email}</h4>
<h4>Powod kontaktu: ${req.body.contactReason}</h4>
<p>Wiadomosc: ${req.body.additionalInfo}</p>
`
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
}
);
So as you can see I'm using the cors module, which is supposed to handle all the cors issues.
But that's not enough. When I get rid of the headers property passed to fetch(), the call is being done, but no data is being sent. When I add the headers, I get the fun
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:4000/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
error again.
How can I get around it and what am I missing?
I used this answer when writing my code: https://stackoverflow.com/a/42965820/7055769
It turns out that CORS only allows some specific content types.
The only allowed values for the Content-Type header are:
application/x-www-form-urlencoded
multipart/form-data
text/plain
The origin parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
fetch('http://localhost:4000/', {
method: 'POST',
mode: 'cors',
headers: {
'Access-Control-Allow-Origin': '*',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
content: body,
}).then(response => response.json()).then(r => console.log(r)).catch(e => console.log(e));
You mind trying this as follow, this should solve the problem :
app.use(function (req, res, next) {
//set headers to allow cross origin requestt
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
Ok there were numerous reasons this didn't work. I'm leaving this answer for the future developers to ease their pain.
This is the method that worked on the client side:
$.ajax({
type: "POST",
url: 'http://localhost:4000/',
data: body,
success: data=>{console.log(data)},
dataType: 'json',
});
Here's my whole server side code:
var express = require('express');
var router = express.Router();
var cors = require('cors');
var app = express();
app.use(cors());
app.options('*', cors());
var a = '=';
router.post('/', (req, res, next) => {
console.log('mailing');
console.log(a);
a += '=';
var nodemailer = require('nodemailer');
var transporter = nodemailer.createTransport({
host: "smtp.gmail.com", // hostname
auth: {
user: 'sqtableknights#gmail.com',
pass: 'testgmail'
}
});
console.log(req.body);
let mailOptions = {
from: `${req.body.name} ${req.body.email}`, // sender address
to: 'alexander.ironside#mygeorgian.ca', // list of receivers
subject: 'Email from UczSieApp contact form', // Subject line
text: 'Hello world ', // plaintext body
html: `
<h4>Imie: ${req.body.name}</h4>
<h4>Email: ${req.body.email}</h4>
<h4>Powod kontaktu: ${req.body.contactReason}</h4>
<p>Wiadomosc: ${req.body.additionalInfo}</p>
`
};
// send mail with defined transport object
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
}
);
module.exports = router;
So in my case I had to add these:
app.use(cors());
app.options('*', cors());
No idea why, but it just breaks without the app.options('*', cors()); parameter. If someone knows a better answer to this, and/or sees any security flaws please leave a comment and let me know. Thank you everybody once more for all the help!
My web server is working fine when I call it through chrome. However when I am using fetch or axiom in my react-app to call the same url, it returns 404 Not Found. The react-app also sends a options request to same url which returns status 200. I have even set this header to allow the origin.
app.use(async (ctx, next) => {
var origin = ctx.headers.origin;
ctx.set({
'Access-Control-Allow-Headers': 'authorization,Content-Type,refresh',
'Access-Control-Allow-Methods': "GET,HEAD,POST,PUT,DELETE",
'Access-Control-Allow-Origin': '*',
'Connection': 'keep-alive',
'Access-Control-Allow-Credentials': true
});
await next();
console.log('______________')
});
require('./routes')(app); //2
my ./routes.js file contain
//router.post('/signin' , signinController.signin);
router.get('/signin' , signinController.signin);
can you please tell me what I am missing here. My axios call
axios.get('http://localhost:3002/signin')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Alright I tried your code out and it works for me if I use app.use(router.allowedMethods()) middleware to pass preflights, OR declare separate option-routes for each route; Or instead of using router.get() there is router.all('/signin', ...) which will also catch options-requests.
This is my complete server code:
const app = new Koa();
const router = new Router();
router.get('/signin' , (ctx, next) => {
ctx.body = '{"status":"hello"}';
});
// Adding a options-route works (instead of router.allowedMethods())
router.options('/signin' , (ctx, next) => {
ctx.body = '';
});
app.use(async (ctx, next) => {
var origin = ctx.headers.origin;
ctx.set({
'Access-Control-Allow-Headers': 'authorization,Content-Type,refresh',
'Access-Control-Allow-Methods': "GET,HEAD,POST,PUT,DELETE",
'Access-Control-Allow-Origin': '*',
'Connection': 'keep-alive',
'Access-Control-Allow-Credentials': true
});
await next();
console.log('______________')
});
app.use(router.routes());
// app.use(router.allowedMethods()); // This works instead of separate option-routes.
app.use((ctx, next) => {
console.log('here');
next();
});
app.listen(9787);
And this is my call:
axios.defaults.headers.common['Authorization'] = "sometoken";
axios.get('http://localhost:9787/signin').then(response =>{
console.log(response); // {data: {…}, status: 200, ... }
});
(I had to add the header or the CORS won't trigger.)
I've tried setting various origin and headers and it does obey your middleware.
But I did notice that if you choose to use allowedMethods(), that will override your Access-Control-Allow-Methods (and make it useless).
It has to do with cross origin support
You can use this package #koa/cors#2 to add cors support
const Koa = require('koa');
const cors = require('#koa/cors');
const app = new Koa();
app.use(cors());
Heres the link to the package
https://github.com/koajs/cors