axios put not happening throwing forbidden - javascript

I am new to axios.
I am trying to do an update to my api through put request. But I am getting the below error.
OPTIONS http://t/Sports/1 403 (Forbidden)
I am researched so many sites for axios but still I am not able to fix the issue
can you tell me how to fix it.
providing my code snippet below
<div className={classes.SportsEditTabContentFooter}>
<div>Sports Status</div>
<div>
<Button variant="outlined" className={classes.button}>
Cancel
</Button>
<Button variant="outlined" onClick={this.saveSports} className={classes.button}>
Save Sports test
</Button>
</div>
</div>
saveSports = () => {
console.log("saveSports---->");
console.log(this.state.Sports);
let saveSports = this.state.Sports;
saveSports.updatedBy = 'raj';
saveSports.priceRuleDescription = "test description";
axios
.put(
'http://t/Sports/' + saveSports.SportsID,
saveSports,
{ headers: { 'Content-Type': 'application/json' } }
)
.then(r => console.log(r))
.catch(e => console.log(e));
//this.toggleDrawer("right", false);
this.setState({ right: false });
this.setState({ snackBarOpen: true });
setTimeout(() => {
this.setState({ snackBarOpen: false });
}, 6000)
};

Since you try communicating different domain because of CORS browser automatically sends OPTIONS request. And backend does not expect this so it returns 403 for whatever reason.
Having this in mind your need
either change your client code to make request simple
place your client code to be run on the same domain where backend runs
run CORS proxy server as the same domain where client code is hosted - since OPTIONS aka preflight request is sent just by browser your code in, say, Node, does not require that
update target backend code to handle preflight OPTIONS request correctly
Each variant is enough to solve your issue. But it's up to you to decide what is more convenient in your case
PS just in case: no, there is no way to avoid preflight OPTIONS request to be sent by configuring axios, replacing axios with different package, fetch() call or native XmlHttpRequest or any other easy change in your client code since it's fundamental (security!) feature of modern web browsers

Related

I'm receiving a 400 bad request error: "A non-empty request body is required" from my fetch request, despite my fetch request having a body

Everytime I make a fetch request from my frontend using the following js code I receive a 400 Bad request status. The body of the response has an error object saying: "A non-empty request body is required".
When I inspect the request section on my devtools network tab it says "no payload for this request". So it looks to me it's not sending the body section of my Fetch.
It does reach the .then() method afterwards.
This is the Typescript Code:
fetch(`api/person/${person.id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(person)
})
.then(() => this.router.navigate(["/"]))
this is the C# backend:
[HttpPut("{id}")]
public IActionResult Put(int id, Person person)
{
person.Id = id;
try
{
var updatedPerson = _personRepository.Update(person);
if (updatedPerson != null)
{
return Ok(updatedPerson);
}
return NotFound();
}
catch (ArgumentNullException)
{
return BadRequest();
}
}
Note that the request doesn't even reach this controller. No break points will be reached if I place any here.
This is a single page application I run from Visual Studio 2019.
It works with postman however, returning the 200 Ok status code and an object back, and reaching backend breakpoints. The request URL contains the int id and the body containing a Json object.
Okay this is not a question that has a clear answer.
Here are steps you could need to take to find out:
Make sure in your fetch request the argument person is really exist, just do console.log(person) before fetch
Make sure server accepts 'application/json' type content. Though in this case the response code should have been different.
Check the response headers, and are the origins of back end and front end are the same? What you need to see are the following:
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Origin: *
Postman works as a native app on your PC and has different way of sending requests rather than your browser, sometimes this causes unclear results.
Here's a way to test what is happening.
Go to your main web site (http://localhost:5001 or whatever) in your
browser
Open up Browser Dev Tools (F12 in most browsers)
copy / paste the following fetch (code below) into your Dev console
& press
What happens? Do you get data back (printed in console)?
This will probably get you to the next step you need to take.
fetch("api/person/1")
.then(response => response.json())
.then(data => console.log(data));

Axios - Handle request with auto-set cookies

I have request which by purpose is sending cookie with token. Here is how it looks-like in Postman:
As you can see in Cookies I receive the token I need to be set in browser. If I open the link from Postman request in browser I get cookie set:
When I use this request with Axios in my code, the cookie is not set in the browser. I am suspecting that I am not using it correctly. What I do is I am calling the method:
axios
.get(`${apiAddress}Users?email=${logEmail}&password=${logPass}`)
.then((res) => {
if (res.status === 200) {
console.log(res.data)
}
})
.catch((e) => {
console.log(e)
});
In this way of use, is it possible this method to set the cookie? Am I doing it right?
If the link is setting cookie when it is opened in browser with correct parameters why it is not working when it is called with Axios?

Javascript Fetch - How to Fix Failed to Fetch Error (probably from making HTTP request on HTTPS site?)

This is the React app (and code). It generates 3 random objects (from list of 500+ objects stored locally). I want to call IconFinder API when the random objects are chosen and just display the icons then (instead of finding 500 icons beforehand).
I'm running it on Windows 10 with Google Chrome Version 84.0.4147.89 (Official Build) (64-bit). The code is hosted on Codesandbox. You can take a look at all the code here or just the output and Chrome dev tools here
Demo XHR GET request that they show in their Docs
var data = null;
var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function () {
if (this.readyState === this.DONE) {
console.log(this.responseText);
}
});
xhr.open("GET", "https://api.iconfinder.com/v4/icons/search?query=arrow&count=10");
xhr.setRequestHeader("authorization", "Bearer <API KEY HERE>");
xhr.send(data);
My Fetch GET request
let url = "https://api.iconfinder.com/v4/icons/search?query=arrow&count=1&premium=0";
let h = new Headers();
h.append("Accept", "application/json");
h.append(
"authorization",
"Bearer <API KEY HERE>"
);
let req = new Request(url, {
method: "GET",
headers: h,
credentials: "include"
});
fetch(req)
.then(response => {
if (response.ok) {
return response;
} else {
throw Error(`Request rejected with status ${response.status}`);
}
})
.then(response => response.json())
.then(data => console.log(data))
.catch(err => console.error("Error: ", err.message));
Output: Console reads Error: Failed to fetch
In the Chrome Dev Tools, Network Tab (Screenshot 1) I see a file of type fetch (Screenshot 2) and file of type json (Screenshot 3 and 4) have something wrong with them.
What I've tried
Fetch GET requests work for Codesandbox with the Star Wars API (no authentication required), but not for MovieDB API (authentication in url not headers - ex. https://api.themoviedb.org/3/search/movi?api_key=<INSERT KEY>?<other parameters here> ). It threw an error because response.ok wasn't true.
I tried fetching data from the IconFinder API and the MovieDB API on other online IDEs (like Scrimba.com and repl.it). Those also didn't work.
I've tried using XHR requests and fetch await requests instead of fetch requests chained with then promises on different platforms. No luck.
I've double-checked how to set the authentication headers with the IconFinder API documentation.
I've also double-checked that my API key is registered to the url I'm calling it from and not restricted to any domains (Screenshot 5)
Looked through these Forums: it looks like I have something going wrong with making fetch requests from a HTTPS page, but I'm not sure what I need to change in my code based on that information. I've tried reloading the page on Codesandbox as http, but it redirects me to https automatically (Source 1, Source 2, Source 3, Source 4)
This is my first time making API calls so I don't really know what the possibilities are for what could go wrong and how to fix it. I've tried looking at some other StackOverflow threads but I'm having a hard time understanding them. Next, I'm going to try transferring the React App to a local file and seeing if I can make fetch requests there. Anyone have any thoughts on what else I should try?
The issue was based on a CORS error. A friend of mine told me to test the api call to:
https://api.iconfinder.com/v4/icons/search?query=arrow&count=1&premium=0
via https://reqbin.com/. It worked on the testing website.
Then, he told me to just make the request to that url with this Cors Anywhere tool. Like this:
https://cors-anywhere.herokuapp.com/https://api.iconfinder.com/v4/icons/search?query=arrow&count=1&premium=0
That worked on my local development environment. Still not sure exactly HOW it works.

How do I do a POST request using the Google Chrome Puppeteer library?

Good Day All,
I'm trying to do a POST request using the puppeteer headless chrome library. I can't seem to get the below code to work.
// Get csrf token
let token = await page.evaluate(() => document.querySelector('[name="CSRFToken"]').value);
let postResponse = await page.evaluate(async(token, cookies) => {
let response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
postData : 'CSRFToken=' + token,
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
console.log('Final response');
console.log(postResponse);
I keep on getting an error that the CSRF token has not been set or that the cookie is invalid.
My question is, am I using the correct method in puppeteer to do a POST? If so, is there any way for me to do some debugging that I can see the actual POST request that was sent?
I appreciate any advice or help. Thanks
You are not creating a request body: hence the error. The postData attribute you set on the request object is not any known attribute, so it won't be set on the request either, meaning that the server will never see your CSRF token. You should look into the MDN docs on fetch().
I believe you should be all good by simply replacing postData with body, but it's hard to know without access to your endpoint. For all we know it might require special headers.
Given that you only post normal form data (which is implied by your key=value code), I would also start using the FormData objects provided by your browser to avoid manual coding of implementation details.
const formData = new FormData();
formData.append("CSRFToken", token);
const response = fetch("/loyalty/points", {
method : 'POST',
cookie : cookies,
body : formData,
headers : {
'cookie' : cookies,
/* other headers you need, possibly content-type (see below) */
},
}).then(response => response.text()).catch(error => console.log(error));
return response;
});
Caveat: using the FormData API will always set the content-type of the data to multipart/form-data. If your server for some reason doesn't support that encoding, and you need to use application/x-www-form-urlencoded (see here for difference),
you can't blindly change the Content-Type: you also need to url encode the content.
For debugging I would simply use a normal Chrome instance to see this. You should be able to run the code there and see the network requests in DevTools (where it would be immediately noticeable that you POST an empty request).

Reactjs with fetch for auth and access token, not able to parse response

I am pretty new to ReactJS.
I am using Chrome browser.
I am trying to create the sign in page using ReactJS. The page is simple with user id and password. Authentication happens on our SSO server, means I have to post data on the server using fetch call and get access_token as a response.
The problem is as below:
I am not getting response in the console. However, when I look at the Network tab on developer tools, I can see that there is a valid response with all required field including access_token in it.
Now sure how should I parse this.
Is this because fetch is async call?
Here is my entire page code.
P.S: some of the code is not getting formatted.
import React, {Component} from 'react';
import '../App/App.css';
import {FormGroup, FormControl, InputGroup} from 'react-bootstrap';
class Auth extends Component {
constructor(props) {
super(props);
this.state = {
userid: '',
password: '',
accessToken: ''
}
}
submit() {
console.log('state', this.state);
const BASE_URL = 'MY SSO URL';
const params = {
'grant_type': 'password',
'username': this.state.userid,
'password': this.state.password,
'client_secret': 'secred',
'client_id': 'client_id',
};
const formData = new FormData();
for (let p in params) {
formData.append(p, params[p]);
}
const headers = {
'Access-Control-Allow-Origin': '*'
};
const request = {
method: 'POST',
headers: headers,
body: formData,
mode: 'no-cors'
};
fetch(BASE_URL, request)
.then((response) => response.text())
.then((responseText) => {
console.log('text',responseText);
})
.catch((error) => {
console.warn(error);
});
console.log('all done');
}
render() {
return (
<div className="login">
<div className="legend">Signin</div>
<FormGroup>
<InputGroup>
<div className="input">
<FormControl
type="text"
placeholder="Enter User Id or email"
onChange={event => this.setState({userid: event.target.value})}
onKeyPress={
event => {
if (event.key === 'Enter') {
this.submit()
}
}}
/>
</div>
<div className="input">
<FormControl
type="password"
placeholder="enter password"
onChange={event => {
console.log(event.target.value)
this.setState({password: event.target.value})
}}
onKeyPress={
event => {
if (event.key === 'Enter') {
this.submit()
}
}}
/>
</div>
<FormControl
type="submit"
onClick={() => this.submit()}
/>
</InputGroup>
</FormGroup>
</div>
)
}
}
export default Auth;
I tried response.json() this gives error as: Unexpected end of input.
As far are your frontend JavaScript code for the fetch(…) request:
mode: 'no-cors'
Remove that. That’s the exact reason your code can’t access the response.
You never, ever want to do mode: "no-cors". The only thing that actually does is to tell the browser, Never let my frontend JavaScript code access the response from this request.
const headers = {
'Access-Control-Allow-Origin': '*'
};
Remove those lines too. Access-Control-Allow-Origin is a response header. You never want to send it in a request. The only effect that’ll have is to trigger a browser to do a preflight.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
I’m guessing that the reason you’re trying mode: 'no-cors' and sending Access-Control-Allow-Origin in the request is that you earlier tried the request without those and you got an error message in the browser console saying that the response lacked Access-Control-Allow-Origin.
If so, there’s no way you can get around that by making changes to your frontend JavaScript code—except by changing your code to instead make the request through a proxy, as outlined in the answer at "No 'Access-Control-Allow-Origin' header is present on the requested resource".
Either that or you need to get the owner of the server at your BASE_URL address to configure the server to send the Access-Control-Allow-Origin in its responses.
Here’s a longer explanation:
Your browser will only let your frontend JavaScript code access responses from cross-origin requests when the servers you’re making the requests to explicitly indicate they’re opting in to receiving cross-origin requests, which they do by sending the Access-Control-Allow-Origin response header in their responses.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS has more details.
Browsers are the only clients that enforce restrictions on cross-origin requests, and they only enforce them on web applications.
That’s why even when you see a No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin … is therefore not allowed access message in your devtools console, you’ll still be able to go to the Network tab in devtools and view the response there.
That’s because the server has sent the response and the browser has received it, but the browser is just refusing to allow your frontend JavaScript code to access the response due to the fact the server sending the response hasn‘t opted into to cross-origin requests by sending the Access-Control-Allow-Origin response header.
The reason you can get the response just fine when you make the request from curl, etc., is that no client other than browsers will refuse to allow your code to access the response if it lacks the Access-Control-Allow-Origin response header. But browsers always will.
And note that in none of this is the server doing any blocking or refusing to respond to any requests. The server always continues to just receive requests and send responses. The only difference is in whether the server sends the Access-Control-Allow-Origin header in the response, or not.

Categories

Resources