So I am trying to send a GET Request in my JavaScript via AJAX. The problem is that I can send the Request in Postman and it works fine. When I use the feature to generate the AJAX code and I insert it in the my local index.html the Request seems to be blocked.
var settings = {
"async": true,
"crossDomain": true,
"url": "http://www.bibsonomy.org/api/posts?resourcetype=bookmark&group=ukp&format=json",
"method": "GET",
"headers": {
"Authorization": "Basic key",
"Cache-Control": "no-cache"
}
}
$.ajax(settings).done(function (response) {
console.log(response);
});
Console output:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource
at https://www.bibsonomy.org/api/posts?resourcetype=bookmark&group=ukp&format=json.
(Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
I have no idea why it is not working and why Postman does not get this error.
Please add Access-Control-Allow-Origin: * in the header of the request.
You should try to add this to your settings
xhrFields: {
withCredentials: true
},
crossDomain: true
This has to be handled from the server side. Only if the server adds a header that the it permits requests from localhost:port(if you are in development),
or you can add
set Access-Control-Allow-Origin: "*" for accepting requests from all clients,
browser will be able to successfully complete the request.
The cross origin validation is a browser provided security against Cross domain attacks. The browser sends a preflight (OPTIONS) request to the server to ensure the request will be a valid one, and on successful return only a valid request will be sent.
So the reliable way to fix this, is a fix in the api provider(server) to accept requests from your domain/localhost.
However you can do a work around for just your browser, you can check this answer for such a method.
Related
I am working on a Google Chrome extension to block a subset of images from posts in a user's Reddit feed based on some backend computer vision run in Python in Google Cloud Storage. The Python code takes a single argument (the URL of an image in Reddit), which is passed in JavaScript via:
const api_url = https://<my-google-chrome-url>
var curUrl = $(this).attr("src")
fetch(api_url,{
method: 'POST',
body: JSON.stringify(curUrl),
headers: {
'Content-Type': 'application/json'
},
})
.then(data => {console.log(data)})
When the extension's code runs, I get the following in the console:
Access to fetch at 'https://this-is-the-path-to-my-google-cloud-function' from origin 'https://www.reddit.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I have tried multiple solutions, enumerated below:
I have followed the instructions here, such that by using Google's gsutil, I am able to confirm the following to be true for the bucket that my function lives in: [{"maxAgeSeconds": 3600, "method": ["GET", "POST"], "origin": ["https://www.reddit.com"], "responseHeader": ["Content-Type"]}]. I have also tried having ["*"] as my origin, to no avail.
I have also tried using in my fetch, mode: no-cors with no success.
Any suggestions or solutions would be greatly appreciated!
For what you mention, the CORS error in this case seems to come from the Cloud Function.
In order to address this, you should configure CORS for the Cloud Function, not Cloud Storage.
CORS consists of the preflight request and the main request. In your function you should check for preflight request by checking if the request's method is OPTION and if so, respond the appropriate headers. Here is a sample:
def cors_enabled_function(request):
# For more information about CORS and CORS preflight requests, see
# https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request
# for more information.
# Set CORS headers for the preflight request
if request.method == 'OPTIONS':
# Allows GET requests from any origin with the Content-Type
# header and caches preflight response for an 3600s
headers = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Max-Age': '3600'
}
return ('', 204, headers)
# Set CORS headers for the main request
headers = {
'Access-Control-Allow-Origin': '*'
}
return ('Hello World!', 200, headers)
For more information, you can read the docs
AJAX call:
$.ajax({
url: "http://myserver2:296/api/Demo/HelloWorld",
type: "GET",
dataType: 'JSONP',
jsonp: "callback",
headers: { 'API_KEY': 'mykey09090' },
success: function (result) {
console.log(result);
},
error: ajaxFailed
});
function ajaxFailed(xmlRequest) {
alert(xmlRequest.status + ' \n\r ' +
xmlRequest.statusText + '\n\r' +
xmlRequest.responseText);
}
I get the following error: Failed to load resource: the server responded with a status of 403 (Forbidden). However when I use Postman, I just have to add the headers with the http://myserver2:296/api/Demo/HelloWorld url it returns the string.
Can I please get some assistance to resolve the issue.
My goal, is to allow the origin server along with the API key correctly provided to get the data back from the Web Api.
Adding the API_KEY header to the request triggers your browser to first send a CORS preflight OPTIONS request. Any headers you add to a request other than headers defined as CORS-safelisted request-headers will trigger your browser to send a CORS preflight OPTIONS request.
I can’t tell for sure but it seems like the 403 you’re seeing is from your server responding to that OPTIONS request, and saying it doesn’t expect to get OPTIONS requests and doesn’t allow them.
The reason you don’t get this from Postman is that unlike browser engines, Postman does not implement CORS, so it does not send the OPTIONS request. (Postman does not operate under the same-origin Web-security model that browsers enforce for Web applications.)
So to make your client app work as expected for scripted cross-origin access to that server, you must configure the server to respond in the right way to that CORS preflight OPTIONS request.
Code dump:
$.ajax({
type: 'GET',
dataType: 'json',
url: api,
xhrFields: {
withCredentials: true
},
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', "Basic [my auth token]");
},
success: function(jd) {
console.log(jd.stringify());
}
});
The problem is that Chrome and Firefox send an OPTIONS preflight when I include a beforeSend, however that OPTIONS request is refused by the API because it doesn't know how to handle an OPTIONS request and treats it like a GET, sees no Authorization header and refuses the request.
The only way I can get this to work is to coerce the browser either to not send an OPTIONS request or include my header with it. I am unable to modify the API that I am using.
I would appreciate it if anyone could advise me.
The reason why browser sends preflight request is that you are using custom headers. Please. read about how to avoid preflight request (content type should be text or html and no custom headers)
If you could not chagne server side the last chance to make it work is to create your custom proxy (for example you can create node server and that node app would take your requests and forward them to those Api Then you will have you own server even in the some domain and this proxy server will send CORS requests to another server domain.
I am trying to make a post call to my (akka-http) backend from scalajs.
The same call is working in postman but failing when i am actually calling from chrome - scalajs
the code in scalajs
ext.Ajax.post(<url>, <json>, headers = Map("Content-Type" -> "application/json"))
I am getting the following error in chrome console
XMLHttpRequest cannot load <url>. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 405.
When i take a look in postman on the code for javascript (generate code snippet) i see the following
var settings = {
"async": true,
"crossDomain": true,
"url": <url>,
"method": "POST",
"headers": {
"content-type": "application/json",
"cache-control": "no-cache",
"postman-token": "273f35c9-1d2a-12d8-30d6-8523d479869e"
},
"processData": false,
"data": <json>
}
$.ajax(settings).done(function (response) {
console.log(response);
});
As mentioned, i can access my backend from postman, not sure what i am missing in scalajs, i was thinking about the crossDomain setting, but if-so i don't know how to set it in my scalajs request.
there is probably some obvious solution.
Also get requests are actually working
EDIT: i am adding backend part akka-http router
respondWithHeaders(`Access-Control-Allow-Origin`.*, `Access-Control-Allow-Methods`(HttpMethods.GET, HttpMethods.POST),
`Access-Control-Allow-Headers`("Origin, X-Requested-With, Content-Type, Accept, Authorization")) {
pathPrefix("..."){...
This is the current state, so what i am missing ?
Thanks for any help.
What is happening here, is that chrome is preventing you from accessing your backend, since:
The backend server is on a different domain than your JavaScript
The backend server does not explicitly allow the domain your JavaScript is on to make calls (that's what the Access-Control-Allow-Origin header means).
Chrome (not the backend) therefore blocks the request.
Since this check happens in the frontend/chrome, the request works very well with postman.
So to fix this properly, you should configure akka-http to add the proper Access-Control-Allow-Origin header.
If you just need to test, you can launch chrome with the flag --disable-web-security.
BE VERY CAREFUL WITH THIS since it makes you (as an internet user) vulnerable to CSRF and other nasty busyness. Do not always use this flag.
I'm developing a javascript app to control some smart TVs but angular pre lights OPTIONS requests before try the POST request (SOAP) I'm trying to send. The devices return a response with a proper Access-Control-Allow-Origin: * but angular refuses to send the POST request.
Of course, I can't change the configurations of the device's server to send another header angular "needs" and I need to send a Cookie and Content-Type.
How can I work around this?
UPDATE with a screenshot of request (bottom) and response (top) headers.
UPDATE with related angular code:
App is configured with:
app.config(['$httpProvider',function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}])
The request is:
var body = '<?xml version="1.0"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1"><IRCCCode>{command}</IRCCCode></u:X_SendIRCC></s:Body></s:Envelope>';
var headers = {
"Content-Type": "text/xml; charset=UTF-8",
"SOAPACTION": "urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"
};
return $http({
method:"POST",
url: "http://{ip}/sony/IRCC".replace("{ip}", config.ip),
data: body.replace("{command}", signal),
headers: headers
});
I believe your problem is withCredentials. When you use withCredentials, the server must indicate that allows credentials. In a simple GET request that doesn't require preflighting, the browser is supposed to keep any such response from your app; in a preflighted request, it should not send the actual request.
Here is the best description at mozilla https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials
It says:
but the browser will reject any response that does not have the Access-Control-Allow-Credentials: true header,
and not make the response available to the invoking web content
If you look at the preflight response, you see the headers:
Access-Control-Allow-Headers: "content-type,soapaction"
Access-Control-Allow-Origin: "*"
But the required Access-Control-Allow-Credentials header is not there.
The Options are only fetched if your browser does not know them,
so if you could beforehand load something from the server (regular not via soap) like including an invisible image, your browser should already know the options and not re request them.