Why does a POST request become a GET request in Microsoft Edge? - reactjs

I'm using Axios and React in my frontend app. When I'm trying to send POST request over HTTPS with Axios (xhr, fetch) and faced with the strange issue - my POST request turns into GET in Edge dev tools.
Here is my request:
const response = await axios.post(
config.local + "/api/login/credentials",
{
login,
password
}
);
Then I tried to dig dipper - created a simple HTTPS server and tried to send POST request from the client.
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
const PORT = 8188;
function handleRequest(req, res){
console.log(req.method);
}
const server = https.createServer(options, handleRequest);
server.listen(PORT, function(){
console.log("Server listening on: https://localhost:" + PORT);
});
And then, as I understand it, that request does not reach the server.
Here are some links:
Issue link 1
Issue link 2

Is there any error in console? You could use Fiddler to trace the network traffic and see the details. Also mentioned in the first link you provided, you could also try the two solutions in your GitHub link:
Solution 1:
My issue is caused by HTTPS; the backend is requiring HTTPS while I send an HTTP post from front side. Now I fixed by changing both to HTTPS.
Or Solution 2:
I solved it by passing the data in a different format using the "URLSearchParams " class.
I had the same problem with:
Microsoft Edge 44.18362.267.0
Microsoft EdgeHTML 18.18362
Windows 10
I think the problem is that Edge only supports certain data types in post requests. If you want to use the content-type 'application/x-www-form-urlencoded' then use URLSearchParams to make it work in Edge and other browsers like Firefox and Chrome. Passing a querystring seems not to work in Edge even if it does in other browsers.
Modifying the original post source code, the result would be:
import Axios from 'axios'
import Promise from 'es6-promise'
Promise.polyfill()
const URL= 'http://192.168.0.112/account/login/username'
// Use URLSearchParams instead:
const dataParams = new URLSearchParams()
dataParams.append('username', 'admin')
dataParams.append('password', 'admin')
Axios.post(URL, dataParams, {
// if you still have problems try more specific options like:
// withCredentials: true,
// crossdomain: true,
// ...
})
.then(res=>{
console.log(res)
}
)
.catch(error=>{
console.log(error)
}
)
Aside from that, the issue in your question is usually caused by CORS. If you use CORS and request an untrusted origin, then Microsoft Edge will only send the GET request and lead to the failure of other requests. You could also refer to this thread to understand why CORS requests fail in Microsoft Edge but work in other browsers. Microsoft Edge also uses Enhanced Protected Mode, the outcome is that: if the site is trusted, it will make two requests, OPTIONS and GET, but if it's not trusted, it only makes the GET request which causes it to fail.

In my case problem was caused by a self-sign certificate. As soon as I started using normal certificate everything began to work.

Related

CORS issue on Localhost, MULTIPLE workarounds have failed

I am in tears as I type this, sobbing into my keyboard
I have wasted over a week trying to understand what is wrong. I can no longer learn or develop. I am going to have to give up learning to code if I cannot fix this.
I understand what CORS is. If I had the ability to edit the API server, I would, but I do not. I must use a 3rd party API. I do not have the time to develop my own to work with. I am UNABLE to develop using anything but a local server. I need to stop CORS issues.
I have been trying to fix this problem for days. I am at a complete standstill with my learning. A week of tears and frustratiion has ben spent on this.
I CANNOT:
use https://cors-anywhere.herokuapp.com. This fails and CORS still screams:
Access to XMLHttpRequest at 'https://cors-anywhere.herokuapp.com/https://randomuser.me/api/?page=1&results=10' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Develop non-locally
Proxy. Package.json just ignores it. I have made multiple attempts to use proxying to avoid CORS. All attempts have ended in complete failure.
I legitimately do not know what to do. This is my code. Please help me, I am in tears and I cannot learn React anymore until this is fixed.
import axios from "axios";
let getFriends = () => {
const config = {
method: "GET",
url: "https://cors-anywhere.herokuapp.com/https://randomuser.me/api/?page=1&results=10",
crossdomain: true,
headers: {
"Content-Type": "application/json"
},
};
return axios(config);
};
export { getFriends };
The reason you are going crazy trying to find a solution is because there is nothing YOU can do about CORS. Changing any header as the other solution recommends won't work, the server will still flag any origins which it does not allow calls from!
This is a value controlled by the SERVER whose API you are calling. And, as the error says, the server you are calling does not accept connections from localhost:3000.
As long as you are making requests from a browser that is on localhost:3000 to this API, you'll be hit with CORS issues.
If you want to ensure that the API itself is not broken, use a different tool like Postman to call to the API. This is like a 'server to server' call, and as such does not require CORS checks.
EDIT: The following call to the random user API seems to work:
import React, { useEffect } from 'react';
function App() {
const fetchRandomUsers = async () => {
const response = await fetch("https://randomuser.me/api/?page=1&results=10")
const json = await response.json()
json.results.forEach((result) => {
console.log(result)
})
}
// On mount, fetch random users
useEffect(() => {
fetchRandomUsers()
}, [])
return (
<></>
);
}
export default App;

Unable to set cookies in Chrome using Flask-JWT-Extended, React, and Axios

Background and Issues
I have a Flask back-end running in localhost:5000 and a React SPA running on localhost:3000.
I was able to make them talk but when trying to store the token generated from Flask into Browser's cookies 1) response headers does not contain any cookies when doing console.log(response) after a successful POST from axios and 2) the cookies are not being set. But when inspecting the network > Login.js header, I could actually see the Set-Cookie key exists as response's header. I've tried multiple solutions from Google and StackOverflow but no solution seems to work here and I really can't figure out what is going on as the request is being made successfully, and Chrome is allowing third party software to set the cookies. And even I can see the tokens from Network > Login.js header.
Steps
1) Users enters in their username and password and hit login.
2) Axios POST call is made to Flask's back-end.
3) Process the data and generates a couple of tokens and set them into cookies.
4) Browser's cookie are set with few tokens. <- this part is not working.
Code
Flask back-end token generation using flask-jwt-extended
# app_config related to flask-jwt-extended
CORS_HEADERS = "Content-Type"
JWT_TOKEN_LOCATION = ["cookies"]
JWT_COOKIE_SECURE = False
JWT_COOKIE_CSRF_PROTECT = True
# post method from flask-restful for LoginAPI class
def post(self):
email = request.json.get("email")
password = request.json.get("password")
# some processing here.....
payload = {
"email": email
}
access_token = create_access_token(identity=payload)
refresh_token = create_refresh_token(identity=payload)
response = jsonify({"status": True})
set_access_cookies(response, access_token)
set_refresh_cookies(response, refresh_token)
return response
CORS using flask-cors
# in below code, I had some issues with putting wildcard (*) into origin, so I've specified to the React SPA's host and port.
CORS(authentication_blueprint, resources={r"/authentication/*": {"origins": "http://localhost:3000"}},
supports_credentials=True)
React SPA - making a post call using axios
# also tried `axios.defaults.withCredentials = true;` but same result.
export const login = (email, password, cookies) => {
return dispatch => {
const authData = {
email: email,
password: password
};
let url = 'http://127.0.0.1:5000/authentication/login/';
axios.post(url, authData, {withCredentials: true)
.then(
response => {
console.log(response)
})
.catch(err => {
console.log(err)
});
dispatch(authSuccess(email, password));
}
};
Below image is the response from successful post call in axios.
I'm not sure whether it is normal but response's headers are not showing any of the cookies that I'm setting from the back-end.
And below image is from Network > header for login/
As shown, you can clearly see the token information with Set-Cookie key. I've also checked that they aren't secure.
And finally when I check my cookie tab from application > cookies, I do not see anything.
So the issues were coming from the localhost.
I have a Flask back-end running in localhost:5000 and a React SPA running on localhost:3000.
From above statement, to be very specific, I was running the back-end on localhost:5000 and running the React SPA on 127.0.0.1:3000.
Once I've changed the 127.0.0.1 to localhost, it worked like a charm.
And a side note, after playing around with CORS, I think it will be a lot easier to use Nginx and proxy_pass to pass the request coming from React SPA to back-end to avoid using CORS completely, because if one have to use the CORS in different environment such as test, staging and etcs, one would have to set up the CORS at the web server level e.g) Nginx anyway and it requires slightly different configuration that how I set up for local environment anyway.

How to fix: CORB block for google chrome (Axios request)

I'm using Django with Rest framework and React to make a call to this API url.
I already enabled CORS, however, the axios request is still blocked by CORB.
Also tried to temporarily disable it, by starting Chrome with the following command line flag:
--disable features=CrossSiteDocumentBlockingAlways,CrossSiteDocumentBlockingIfIsolating
Here is the code:
componentDidMount() {
const articleID = this.props.match.params.articleID;
axios.get(`http://127.0.0.1:8000/api/${articleID}`, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Content-Type': 'application/json',
'X-Content-Type-Options': 'nosniff'
}
}).then(res => {
this.setState({
article: res.data
});
console.log(`http://127.0.0.1:8000/api/${articleID}`);
//console.log(res.data);
});
}
This is the error
WARNING: Cross-Origin Read Blocking (CORB) blocked cross-origin response http://127.0.0.1:8000/api/1 with MIME type application/json.
How to defeat CORB and allow javascript to access local web server running on localhost (127.0.0.1) over XHR:
Select a random domain and point it to 127.0.0.1 in your HOSTS file
Direct your XHR connections to that domain instead of 127.0.0.1
You will need to enable SSL/TLS on your local web server.
a) If you are coding your own sockets server in C here is a guide on how to SSL enable them.
b) Or you can base your simple local server on a light web server that supports SSL/TLS out of the box: abyssws I chose this faster solution and had it serve files dynamically dumped out by my existing logic to specific doc paths under the server's root.
You will need to make sure that your local server's responses always include this CORS header: Access-Control-Allow-Origin: *
It should be working now.
SOLVED: added Allow-Control-Allow-Origin extension to my chrome browser and specified URL pattern. For example, localhost:8000/* and http://127.0.0.1:8000/* should be able to connect. If CORB error comes up, there's no way but to disable the chrome browser security for me :(

Can't connect to API using React.js fetch method

I'm trying to connect to buffer's API (https://buffer.com/developers/api/oauth) via react.js using fetch(), but I'm getting a 400 error response.
This is running on my localhost but the site's accessible from the Internet.
Here's my code:
const queryString = require('query-string');
const parsed = queryString.parse(window.location.search);
const buffer_data = {
client_id: BUFFER_CLIENT_ID,
client_secret: BUFFER_CLIENT_SECRET,
redirect_uri: BUFFER_CALLBACK_URL,
code: parsed.code,
grant_type: 'authorization_code',
};
fetch(BUFFER_ACCESS_TOKEN_URL, {
method: 'post',
body: JSON.stringify(buffer_data),
}).then( data => {
console.log('data response ' + data);
return data.json();
}).then( response => {
console.log(response);
});
And here's the response:
{"error":"invalid_request","error_description":"Invalid grant_type
parameter or parameter missing"}
And the console prints this:
Failed to load https://api.bufferapp.com/1/oauth2/token.json: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://myserver.com' is therefore not allowed
access. The response had HTTP status code 400. If an opaque response
serves your needs, set the request's mode to 'no-cors' to fetch the
resource with CORS disabled.
I've tried lots of things, like not serializing the data, trying sending many different headers, using a CORS chrome plugin, etc
Before coding this in react, I've successfully connected using PHP, but to do that I had to add an SSL certificate on my server.
I'm also open to use any library but haven't found one to do this job. Or any other fetching method, like axios?
Many thanks!
I don't know which browser you are using, but you might want to add Allow-Control-Allow-Origin
for your chrome browser (if you are using chrome). This is some issue that seems to occur when you are using localhost with chrome.
Also, i highly recommend using axios for fetching API's, it comes with some easy error logs that can help you pinning down the issue pretty fast.
Greetings!

Bad Request (400) When Trying to Authenticate Harvest API in React

So I'm building a status board for our internal use as developers here in the office. It will show number of commits, hours tracked, etc.
I am following this model for authenticating. After a user logs in with harvest it redirects them back to the app with the code param as a query string, I'm then taking that query string and passing it to a state to then do a fetch to get the access token (so that I can later pull API data).
What happens, is the login is successful but when you are redirected back to the app the fetch throws a Bad Request (400) error. I have tested in Postman and can get the correct response so I'm not sure what the issue is...
Here is some of the JS from the Main component that sets the states if there is a code param:
harvestState() {
// grab URL params
let urlParams = queryString.parse(location.search);
console.log(urlParams);
console.log(urlParams.code);
// set the state based on the paramater passed back
urlParams.code ? (
this.setState({
harvestcode: urlParams.code
})
) : (
this.setState({
harvestcode: 'none'
})
);
}
componentWillMount(){
this.harvestState();
}
And here is the fetch function in my Harvest component:
getHarvest(){
const clientSecret = 'XXXXXXXXXX';
// Set Harvest Headers
const harvestHeaders = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'POST',
mode: 'no-cors',
body: {
'code': this.props.code,
'client_id': this.props.clientid,
'client_secret': clientSecret,
'redirect_uri': 'http://dash.mycompany.me',
'grant_type': 'authorization_code'
}
};
fetch('https://mycompany.harvestapp.com/oauth2/token', harvestHeaders)
.then( response => response.json() )
.then( token => {
console.log(token);
} )
}
componentDidMount(){
if( this.props.code !== 'none' ){
this.getHarvest();
}
}
Is there something here that I am doing wrong? Why does it always return a bad request? Any help would be appreciated. Thank you!
At least one issue you have is that when you use mode: 'no-cors' you’re telling the browser to handle the response as an opaque response, which means that you’re telling the browser to not make any properties of the response object accessible from JavaScript.
So if you make a mode: 'no-cors' request, response => response.json() is going to fail.
The only purpose for no-cors in practice is in combination with Service Workers when you’re just caching resources (e.g., images) from responses, without need to get properties of the responses.
Anyway, given that the client Web app making the requests in your deployment is running from a different origin than the server the requests are sent to, browsers are going to block the requests unless the server responds with the necessary CORS headers—Access-Control-Allow-Origin, for a start. For an explanation, see the MDN article HTTP access control (CORS).
That is, browsers block cross-origin requests made from JavaScript unless the server the requests are sent to opts-in to allowing those, with the Access-Control-Allow-Origin, etc., response headers. The reason Postman doesn’t block such requests is that Postman is not an arbitrary Web app running at some specific origin on the Web but is instead a browser plugin that you’ve intentionally installed. So it’s not bound the cross-origin restrictions browser enforce for Web apps.

Resources