I wrote a simple nodejs server to allow a local web page to proxy remote data by $.ajax call) and avoid CORS problems.
Everything is working but the last call: this one is a POST call with a number of form input data that I need to turn to the remote server.
The request is received by the server but it doesn't receive the form data.
The code is:
function saveDati(req, resp) {
var url = "https://www.xyz.xyz/web/call?portlet.action=saveDataForm"
fetch(url, {
method: 'POST',
mode: 'no-cors',
body: req.body,
})
.then((resp1) => {
return resp1.text()
})
.then((risp2) => {
console.log(risp2)
resp.header("Access-Control-Allow-Origin", "*");
resp.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
resp.send(risp2);
console.log(".. sent")
})
.catch((err) => console.log(err))
}
How can I send the form data correctly?
I think you need a header like this
function saveDati(req, resp) {
var url = "https://www.xyz.xyz/web/call?portlet.action=saveDataForm"
fetch(url, {
method: 'POST',
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
mode: 'no-cors',
body: req.body,
})
.then((resp1) => {
return resp1.text()
})
.then((risp2) => {
console.log(risp2)
resp.header("Access-Control-Allow-Origin", "*");
resp.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
resp.send(risp2);
console.log(".. sent")
})
.catch((err) => console.log(err))
}
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 hosted website on two different platforms like Firebase and Heroku
I Have some issues with that
Firstly, It showing cors errors when I post data from firebase hosted URL to the server which is hosted on Heroku
Then after resolving cors errors data couldn't from the server it showing undefined in console
Here is my server-side code which is hosted on Heroku
const express = require('express')
const path = require('path')
const PORT = process.env.PORT || 3000
const app = express()
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({extended:false}))
app.use(bodyParser.json())
app.use(express.json({limit:'1mb'}))
app.use(function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'https://sample-377b8.web.app');
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With,content-type,Accept,Authorization',);
res.header('Access-Control-Allow-Credentials', true);
if(req.method=="OPTIONS"){
res.header('Access-Control-Allow-Methods','PUT,POST,DELETE,PATCH')
return res.status(200).json({})
}
// Pass to next layer of middleware
next();
});
let data;
app.get('/',(req,res)=>{
res.send("hello world")
})
app.post('/',(req,res)=>{
data = req.body
console.log(data)
res.status(200).json({
"success":"200 response",
"res":"You are now just talked with server"
})
})
app.listen(PORT, () => console.log(`Listening on ${ PORT }`))
This is my client side code
document.getElementById('send').addEventListener('click',async()=>{
let data = {lat,lon}
await fetch('https://demoserver-app.herokuapp.com/',{mode:"no-cors"},{
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then( async (dat) =>{
console.log(res.json())
}).then(res =>{
console.log(res)
})
})
It is giving the error on a console like
console error image
Headers information in the network tab
Header information of request image
I hope I can help you,
one issue that I see that can make this kind of output
is that you console.log(res) but .then referring to (dat)
And I don''t think you need async inside .then(it's already async function)
try this:
document.getElementById('send').addEventListener('click',async()=>{
let data = {lat,lon}
await fetch('https://demoserver-app.herokuapp.com/',{mode:"no-cors"},{
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
}).then( data =>{
data.json()
}).then(res =>{
console.log(res)
})
})
ok, so for the server side:
1)you need to destructure data from req.body, what you made is just adjust req.body to data bar.(see my solution)
2) for the post method you need to make a directory and not try it in the root directory.
try this code you will see the response you want
server:
app.post('/getmessage', (req,res) => {
const {data} = req.body;
console.log(data);
res.status(200).json({
"success":"200 response",
"res":"You are now just talked with server"
})
})
client:
fetch('http://localhost:3000/getmessage', {
method : 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
data:"this is massage from client"
})
})
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.log(err))
I am trying to post some data to my nodejs server using fetch api but it seems the fetch request never reaches my server..
Fetch code
const resp = await fetch("http://localhost:5000/api/students/", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: `{
"name": "Ahmed",
"seat": 4
}`
});
console.log(resp);
const json = await resp.json();
return json;
nodeJS post body
route.post("/", CORS, async (req, res) => {
console.log('abc', req.body);
const {
error
} = validateStudent(req.body);
if (error) return res.status(400).send(error.details[0].message);
const result = await addStudent(req.body);
if (!result) return res.status(400).send("Student cannot be added");
res.status(200).send(result);
});
code of CORS middleware
console.log('avcx');
res.header("Access-Control-Allow-Origin", "*").header(
"Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
console.log('acvced');
next();
As you can see I've done some logs on my server but nothing shows up... BTW eveything is working fine with get request..
sending the same request with postman works fine.
I don't know why I'm getting this error I tackled this error for GET requests by creating a middleware 'CORS' but I'm still getting this error for POST request:-
Thanks in advance :)
I solved this problem. I wasn't handling the incoming requests correctly because I didn't know that fetch sends a preflight request with an OPTION method before sending the actual POST request. So I solved it by adding this line in my index file above every other request which will be executed every time a request (with any method) is made.
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*").header(
"Access-Control-Allow-Credentials", true);
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", " GET, POST, PUT, PATCH, POST, DELETE, OPTIONS");
next();
});
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
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();
});