Fetch Request Completes Successfully, but Response Object Empty - javascript

I have a fetch request within the componentDidMount() method of a React component:
const request = new Request(url, {
mode: 'no-cors',
method: 'get',
headers: {
Accept: 'application/json'
}
});
fetch(request)
.then(function(response) {
console.log('Response: ', response);
return response.text();
})
.then(function(data) {
// _this.setState({ data: data });
console.log('Success: ', data);
console.log('Request succeeded with JSON response', data);
}).catch(function(error) {
console.log('Request failed', error);
});
When the Component loads, I can see the Request being made in the Console and the proper data being returned; however, my Response object is always empty:
Response { type: "opaque", url: "", redirected: false, status: 0, ok: false, statusText: "", headers: Headers, bodyUsed: false }
response.text() returns null, and I'm really uncertain what is going on. I've used the same method before and not had this problem, so I'm uncertain if it's different because of the third-party data source or what.
Any ideas?

I suggest you to follow the comments below the question:
sideshowbarker says
If the reason you’re using mode: 'no-cors' is because the server doesn’t send the Access-Control-Allow-Origin response header in its responses, then mode: 'no-cors' is not the way to fix that. The only way to fix it properly is to either configure the server to send Access-Control-Allow-Origin response header or else change your frontend JavaScript code to make you request through a proxy instead. follow this link...

Related

Cant get data from express server

I am trying to send a GET request and receive a response on my client side (react).
On my express server:
app.get('/', function (req, res) {
res.send('Hey, I came from the express server');
})
When I use postman to sent the request I receive a good answer:
So I don't think the problem is with the server.
A problem:
When I try to send the request using react like this:
const getData = () => {
fetch("http://localhost:8081", {
method: "GET",
mode: 'no-cors'
}).then(response => console.log(response));
}
For some reason the response status is 0 and not 200 (I am receiving status code of 200 when checking this request with postman and also on the chrome network tab).
In addition, if I try to print response.body it will be null.
The response:
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
[[Prototype]]: Response
What am I doing wrong here?
You can add a proxy property to your package.json:
"proxy": "http://localhost:8081",
And then just use / as your fetch endpoint.
fetch('/'...
You need to transfer your response to an text or json like:
const getData = () => {
fetch("http://localhost:8081", {
method: "GET",
mode: 'no-cors'
}).then(response => response.json()).then(data => console.log(data))
}
Besides .json() there are even more methods. Its everything written down in the docs. You just need to google it:
https://developer.mozilla.org/en-US/docs/Web/API/Response#methods

Unable to access cookie from fetch() response

Even though this question is asked several times at SO like:
fetch: Getting cookies from fetch response
or
Unable to set cookie in browser using request and express modules in NodeJS
None of this solutions could help me getting the cookie from a fetch() response
My setup looks like this:
Client
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'same-origin',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
...
function handleSubmit(e) {
e.preventDefault();
registerNewUser({...values, avatarColor: generateAvatarColor()}).then(response => {
console.log(response.headers.get('Set-Cookie')); // null
console.log(response.headers.get('cookie')); //null
console.log(document.cookie); // empty string
console.log(response.headers); // empty headers obj
console.log(response); // response obj
}).then(() => setValues(initialState))
}
server
private setUpMiddleware() {
this.app.use(cookieParser());
this.app.use(bodyParser.urlencoded({extended: true}));
this.app.use(bodyParser.json());
this.app.use(cors({
credentials: true,
origin: 'http://localhost:4200',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
credentials: true
}));
this.app.use(express.static(joinDir('../web/build')));
}
...
this.app.post('/register', (request, response) => {
const { firstName, lastName, avatarColor, email, password }: User = request.body;
this.mongoDBClient.addUser({ firstName, lastName, avatarColor, email, password } as User)
.then(() => {
const token = CredentialHelper.JWTSign({email}, `${email}-${new Date()}`);
response.cookie('token', token, {httpOnly: true}).sendStatus(200); // tried also without httpOnly
})
.catch(() => response.status(400).send("User already registered."))
})
JavaScript fetch method won't send client side cookies and silently ignores the cookies sent from Server side Reference link in MDN, so you may use XMLHttpRequest method to send the request from your client side.
I figured it out. The solution was to set credentials to 'include' like so:
export async function registerNewUser(payload) {
return fetch('https://localhost:8080/register',
{
method: 'POST',
body: JSON.stringify(payload),
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
}
After that I needed to enabled credentials in my cors middleware:
this.app.use(cors({
credentials: true, // important part here
origin: 'http://localhost:4200',
optionsSuccessStatus: 200
})
And then finally I needed to remove the option {httpOnly: true} in the express route response:
response.cookie('token', '12345ssdfsd').sendStatus(200);
Keep in mind if you send the cookie like this, it is set directly to the clients cookies. You can now see that the cookie is set with: console.log(document.cookie).
But in a practical environment you don't want to send a cookie that is accessible by the client. You should usually use the {httpOnly: true} option.

Node/Express - res.status().send() only sends the status but does not send an object

I am having an issue with a route in my backend where res.status().send() will only send the client the status code, but it will not send the client the object located inside of send().
Here is my code (redacted all code but the problem for brevity):
exports.user_signup = (req, res) => {
const { body } = req;
const { companyName, password, email } = body;
User.find({ email: email }, (err, previousUsers) => {
if (err) {
return res.status(400).send({
message: "There was an issue signing up."
});
} else if (previousUsers.length > 0) {
return res.status(403).send({
message: "Records show this email is linked to another account."
});
}
}
When I make my fetch request from the client, the response only returns the status code from the server, but nowhere in the response is the object in the send() method on the server. Just spitballing, I threw res.status(200).json(object) at it to send the object as json to no avail.
Here is my `fetch request from the client:
fetch("http://localhost:3000/users/accounts/", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
}).then(response => console.log(response));
}
To show what response I am getting, I purposely posted some form data from the client to the route that would throw the 403 error, and this is the response I get in the browser console:
Response {type: "basic", url: "http://localhost:3000/users/accounts/", redirected: false, status: 403, ok: false, …}
So I am able to successfully send the status back from the route to the client, however I can not for the life of me figure out why send() does not send the object along with it.
The body of the response that comes back from fetch() is a ReadableStream. You need to process it to turn it into something usable. Normally you would call response.json() to parse it as a JSON object:
fetch("http://localhost:3000/users/accounts/", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
})
.then(response => response.json())
.then(response => console.log(response));
}

Vue.js Fetch throws 404 and api response

I can't make a POST request in Vue.js. It was giving me CORS issues, but I added
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
to the API and they went away. I can get valid responses from the API using Postman while using the same email and password (Postman ignores CORS).
Here is my Fetch request:
<script>
export default {
data () {
return {}
},
methods : {
login : function () {
console.log('Logging in');
// axios({
// method : 'post',
// url : 'https://www.example.com/login',
// headers : {'content' : 'application/json'},
// data : {
// email : 'emailHere',
// password : 'passwordHere'
// }
// })
// .then(function (response) {
// console.log(response);
// })
// .catch(function (error) {
// console.log(error);
// });
fetch('https://www.example.com/login', {
method: 'POST',
body: JSON.stringify({
email : 'emailHere',
password : 'passwordHere'
})
})
.then((res) => res.json())
.then((data) => console.log(data))
.catch((err) => console.error(err))
}
}
}
</script>
https://www.example.com/api/v1/authenticate/login 404 (Not Found)
{status: false, message: "Invalid credentials"}
I tried Axios, and still gives me 404, but not the "Invalid Credentials" response.
In other applications I have used jquerys ajax successfully with the same API, so the API seems to allow javascript requests. But Fetch and Axios don't like it.
I have a Login.vue component that has a button
<a id="login-btn" #click.prevent="login">{{ $t('loginPage.loginButtonText') }}</a>
Any help would be appreciated! Thanks!
You are missing Content-Type header. Try setting headers in your request. Fetch demands that you set headers explicitly since it is a low-level API. Your server may reject as it doesn't recognize appropriate Content-Type. Try this:
fetch('https://www.example.com/login', {
method: 'POST',
// THIS IS IMPORTANT
headers: new Headers({
'Content-Type': 'application/json',
'Accept': 'application/json',
}),
body: JSON.stringify({
email : 'emailHere',
password : 'passwordHere'
})
})
Also, remember two things with fetch:
First getting 404 using fetch doesn't mean that your request has failed. If a server responds 4xx or 5xx error, then fetch is considered successful. Only when a network error occurs, fetch is rejected. So if you get 404, it means the request has reached server but there is a problem with the client side.
Second, try setting mode to cors in you fetch request. Thought the default value of mode is cors.

JS Fetch takes only OPTIONS request and print that out

Im trying to make a request from my React App to my backend server, the frontend do a OPTIONS request and that is OK, the problem is that my then on the fetch console logs the OPTIONS response, and not the real response that is made efter the OPTIONS request.
fetch('http://localhost:8080/api/kp/ticket', {
headers: {
"token": sessionStorage.getItem('token')
},
mode: 'cors',
method: 'GET'
}).then(data => console.log(data));
try this
fetch('http://localhost:8080/api/kp/ticket', {
headers: {
"token": sessionStorage.getItem('token')
},
mode: 'cors',
method: 'GET'
}).then(data => (data.json())
.then(res => console.log(res));
Check in "Other" tab in chrome devtools. Not in XHR

Categories

Resources