I'm trying to fetch some data from the REST API of HP Alm. It works pretty well with a small curl script - I get my data.
Now doing that with JavaScript, fetch and ES6 (more or less) seems to be a bigger issue. I keep getting this error message:
Fetch API cannot load . Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:3000' is therefore not allowed access. The response had HTTP status code 501. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I understand that this is because I am trying to fetch that data from within my localhost and the solution should be using CORS. Now I thought I actually did that, but somehow it either ignores what I write in the header or the problem is something else?
So, is there an implementation issue? Am I doing it wrong? I can't check the server logs unfortunately. I'm really a bit stuck here.
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('GET', 'POST', 'OPTIONS');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(sign_in, {
//mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
I am using Chrome. I also tried using that Chrome CORS Plugin, but then I am getting another error message:
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'. Origin 'http://127.0.0.1:3000' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
This question is related to
javascript
cors
fetch-api
preflight
access-control-allow-origin
In my case, web server prevented "OPTIONS" method
Check your web server for the options method
I'm using "webtier"
/www/webtier/domains/[domainname]/config/fmwconfig/components/OHS/VCWeb1/httpd.conf
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
change to
<IfModule mod_rewrite.c>
RewriteEngine off
RewriteCond %{REQUEST_METHOD} ^OPTIONS
RewriteRule .* . [F]
</IfModule>
The problem arose because you added the following code as request header in your front-end :
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Those headers belong to response, not request. So remove them, including the line :
headers.append('GET', 'POST', 'OPTIONS');
Your request had 'Content-Type: application/json'
, hence triggered what is called CORS preflight. This caused the browser sent the request with OPTIONS method. See CORS preflight for detailed information.
Therefore in your back-end, you have to handle this preflighted request by returning the response headers which include :
Access-Control-Allow-Origin : http://localhost:3000
Access-Control-Allow-Credentials : true
Access-Control-Allow-Methods : GET, POST, OPTIONS
Access-Control-Allow-Headers : Origin, Content-Type, Accept
Of course, the actual syntax depends on the programming language you use for your back-end.
In your front-end, it should be like so :
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
headers.append('Origin','http://localhost:3000');
fetch(sign_in, {
mode: 'cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
I was working with Spring REST, and I solved it adding the AllowedMethods into the WebMvcConfigurer.
@Value( "${app.allow.origins}" )
private String allowOrigins;
@Bean
public WebMvcConfigurer corsConfigurer() {
System.out.println("allow origin: "+allowOrigins);
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//.allowedOrigins("http://localhost")
.allowedOrigins(allowOrigins)
.allowedMethods("PUT", "DELETE","GET", "POST");
}
};
}
With Nodejs, if you are using routers, make sure to add cors before the routers. Otherwise, you'll still get the cors error. Like below:
const cors = require('cors');
const userRouter = require('./routers/user');
expressApp = express();
expressApp.use(cors());
expressApp.use(express.json());
expressApp.use(userRouter);
Remove this:
credentials: 'include',
In my case,I use the below solution
Front-end or Angular
post(
this.serverUrl, dataObjToPost,
{
headers: new HttpHeaders({
'Content-Type': 'application/json',
})
}
)
back-end (I use php)
header("Access-Control-Allow-Origin: http://localhost:4200");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header("Access-Control-Allow-Headers: Content-Type, Authorization");
$postdata = file_get_contents("php://input");
$request = json_decode($postdata);
print_r($request);
Just my two cents... regarding How to use a CORS proxy to get around “No Access-Control-Allow-Origin
header” problems
For those of you working with php at the backend, deploying a "CORS proxy" is as simple as:
create a file named 'no-cors.php' with the following content:
$URL = $_GET['url'];
echo json_encode(file_get_contents($URL));
die();
on your front end, do something like:
fetch('https://example.com/no-cors.php' + '?url=' + url)
.then(response=>{*/Handle Response/*})`
Try adding all these headers in this code below Before every route, you define in your app, not after the routes
app.use((req, res, next) =>{
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers','Origin, X-Requested-With, Content-Type,Accept, Authortization');
res.setHeader('Acces-Control-Allow-Methods','GET, POST, PATCH, DELETE');
adding mode:no-cors
can avoid cors issue in the api.
fetch(sign_in, {
mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
Hi @daniel.lozynski. Access-Control-Allow-Origin
is one of the worst problems web developers face when working with APIs, and I've been working on solutions for a long time.
One way to get rid of Access-Control-Allow-Origin
is to use proxies. Of course, proxies sometimes have their own problems.
too many requests
error. Of course, this problem is eliminated by switching between proxies.However, these are all temporary problems and only occur to you during development.
Below is a list of the best proxies I have ever found.
You can easily equip the API with a proxy and get rid of Access-Control-Allow-Origin
by adding any of these addresses before your IP address.
Consider a few examples below:
Use of proxies is limited to online APIs. And you can not use proxies in local APIs. In the following, I will tell you to answer for local APIs as well...
I recently came across a very good Chrome extension that has not had those two proxy problems for me so far and I am very happy with it since I used it.
But the only problem with using this plugin is that you can no longer debug your project on your mobile phone with IP address. This is because this plugin only creates a proxy on your browser and no longer affects data transmission over cable by IP.
You can find and install this plugin from this link.
Allow CORS: Access-Control-Allow-Origin
You can just install this extension on your Chrome browser and have fun...!
Using this plugin is very, very simple and you just need to install it and then activate it. However, if you have a problem with it, on the page of this plugin in 'Chrome Extensions', there is a YouTube video that will completely solve your problems by watching it.
Because my favorite browser is to develop Chrome, I did not look for solutions for other extensions. So if you use Chrome, this plugin will be very useful for you as well.
This error occurs when the client URL and server URL don't match, including the port number. In this case you need to enable your service for CORS which is cross origin resource sharing.
If you are hosting a Spring REST service then you can find it in the blog post CORS support in Spring Framework.
If you are hosting a service using a Node.js server then
npm install cors --save
Add following lines to your server.js
var cors = require('cors')
app.use(cors()) // Use this after the variable declaration
In case you are using NodeJS/Express as back-end and ReactJS/axios as front-end within a development environment in MacOS, you need to run both sides under https. Below is what it finally worked for me (after many hours of deep dive & testing):
Step 1: Create an SSL certificate
Just follow the steps from How to get HTTPS working on your local development environment in 5 minutes
You will end up with a couple of files to be used as credentials to run the https server and ReactJS web:
server.key & server.crt
You need to copy them in the root folders of both the front and back ends (in a Production environment, you might consider copying them in ./ssh for the back-end).
Step 2: Back-end setup
I read a lot of answers proposing the use of 'cors' package or even setting ('Access-Control-Allow-Origin', '*'), which is like saying: "Hackers are welcome to my website". Just do like this:
import express from 'express';
const emailRouter = require('./routes/email'); // in my case, I was sending an email through a form in ReactJS
const fs = require('fs');
const https = require('https');
const app = express();
const port = 8000;
// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "https://localhost:3000");
next();
});
// Routes definition
app.use('/email', emailRouter);
// HTTPS server
const credentials = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
const httpsServer = https.createServer(credentials, app);
httpsServer.listen(port, () => {
console.log(`Back-end running on port ${port}`);
});
In case you want to test if the https is OK, you can replace the httpsServer constant by the one below:
https.createServer(credentials, (req: any, res: any) => {
res.writeHead(200);
res.end("hello world from SSL\n");
}).listen(port, () => {
console.log(`HTTPS server listening on port ${port}...`);
});
And then access it from a web browser: https://localhost:8000/
Step 3: Front-end setup
This is the axios request from the ReactJS front-end:
await axios.get(`https://localhost:8000/email/send`, {
params: {/* whatever data you want to send */ },
headers: {
'Content-Type': 'application/json',
}
})
And now, you need to launch your ReactJS web in https mode using the credentials for SSL we already created. Type this in your MacOS terminal:
HTTPS=true SSL_CRT_FILE=server.crt SSL_KEY_FILE=server.key npm start
At this point, you are sending a request from an https connection at port 3000 from your front-end, to be received by an https connection at port 8000 by your back-end. CORS should be happy with this ;)
Using dataType: 'jsonp'
worked for me.
async function get_ajax_data(){
var _reprojected_lat_lng = await $.ajax({
type: 'GET',
dataType: 'jsonp',
data: {},
url: _reprojection_url,
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
},
success: function (data) {
console.log(data);
// note: data is already json type, you
// just specify dataType: jsonp
return data;
}
});
} // function
Source: Stackoverflow.com