I have setup a small web application on heroku.com in Django which returns JsonResponse you can see it here.
{
name: "shubham",
college: "MAIT",
subject: "java"
}
And I also setup server locally on my computer which accepts that JSON and it appends with HTML element here my javascript file :
$(function (){
$.ajax({
type:'GET',
url:'https://justgiveme.herokuapp.com/',
dataType :"Json",
contentType: "application/json; charset=utf-8",
success: function(data) {
alert("Success !");
},
error : function()
{
alert("failed !");
}
});
});
but when I open localhost it gives me alert("failed !") instead of alert("success !"); .
I have check on Chrome console and I found this error :
Any helpful suggestion is appreciable .
You need to enable Cross-Origin-Resource-Sharing (CORS) on your heroku app. Right now its failing because the request isn't coming from the domain which the first resource was retrieved from. In your case, 127.0.0.1.
Here's a starting point for Django on CORS: http://www.django-rest-framework.org/topics/ajax-csrf-cors/
The error you are seeing is because the browser sends a preflight request to check if a cross origin request is allowed. You can see it being sent when viewing the Network tab in the Chrome Inspector. It will be an OPTIONS request to the url that is specified in the ajax.
In order to resolve this issue, the server needs to let the browser know that cross origin requests are allowed. To do this, Django must respond to the preflight request with the Access-Control-Allow-Origin header specified. The header's value must be either be the website you are requesting from or "*" to allow any website.
//Any website
Access-Control-Allow-Origin: *
//Specific website
Access-Control-Allow-Origin: http://www.example.com
A resource makes a cross-origin HTTP request when it requests a
resource from a different domain than the one which the first resource
itself serves. For example, an HTML page served from
http://domain-a.com makes an src request for
http://domain-b.com/image.jpg. Many pages on the web today load
resources like CSS stylesheets, images and scripts from separate
domains.
For security reasons, browsers restrict cross-origin HTTP requests
initiated from within scripts. For example, XMLHttpRequest follows
the same-origin policy. So, a web application using XMLHttpRequest
could only make HTTP requests to its own domain. To improve web
applications, developers asked browser vendors to allow XMLHttpRequest
to make cross-domain requests
you can read more about CORS here .
Detailed explanation of how to setup CORS in Django ?
This is because of no provision in the REST API to handle Cross-Origin-Resource-Request (CORS). To enable it in the REST API, we need django-cors-headers as recommended in Django REST Framework documentation. The minimal settings required are as follows.
Step 0 - install django-cors-headers .
pip install django-cors-headers
Step 1 - In settings.py, add the following entry in INSTALLED_APPS tuple.
INSTALLED_APPS = (
'......',
'corsheaders',
'......'
)
Step 2 - In settings.py, add the following entries at the top of MIDDLEWARE_CLASSES tuple.
MIDDLEWARE_CLASSES = (
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
)
Step 3 - Add the following flag variable in settings.py
CORS_ORIGIN_ALLOW_ALL = True
you can read more about CORS in django here .
We are done !!
Related
I'm developing a web app in Angular 10 that works as follows:
I'm dealing with CORS issue. I do not have permission to add code to the server I'm fetching.
I want to be able to:
Fetch the website
Parse the result, and put it in my database
I'm aiming to deploy the solution on an Apache server.
Here is the CORS error I'm dealing with:
Blocking a Cross-Origin Request: The "Same Origin" policy does not
allow viewing the remote resource located at
https://wwwfrance1.CENSORED.eu.com/api/?apikey=CENSORED.
Reason: "Access-Control-Allow-Origin" CORS header is missing. Status
code: 200.
Here is what i've tried:
Using MOSIF mozilla extension (works, but not sustainable for deployment, and for some reason, when I'm ignoring the CORS security, I cannot post on my DB any more)
Adding a header in my fetching request, such as:
/******API SEACH****/
/***Global Update***/
private updateClients() {
let xmlRequestPromise = fetch('https://wwwfrance1.CENSORED.eu.com/api/?apikey=CENSORED&service=list_clients', {
method: 'GET',
headers: {
'Access-Control-Allow-Origin': '*',
}
})
.then(async response => this.clients = this.regexSearchClient(await response.text()))
return xmlRequestPromise
}
But that doesn't work either. I've verified that the header appears in the request.
How to proceed?
What is CORS ?
Cross-origin resource sharing is a mechanism that allows restricted resources on a web page to be requested from another domain outside the domain from which the first resource was served. From wiki
In simple terms only an internal webserver can send Requests which are potentially dangerous to it's web server, and requests from other server's are simply blocked.
But few HTTP requests are allowed ,Few of the allowed methods are GET, HEAD, POST.
How do I resolve the issue ?
Apparently in this circumstance you cannot send a fetch request to a web server having CORS header. Instead you can do a GET request to the web server as a web server having CORS allows HTTP GET requests.
Note - If you send a GET request to a web server using angular in your browser it wouldn't work as browser's convert GET requests into fetch requests and fetch requests aren't allowed from a web server with CORS. Instead send a GET request from a webserver/local machine rather than a browser.
Create your own server and make a route which fetches that API. From your Angular application fetch that route on your server.
You have to use a package as a middleware. If you are using nodejs-framework expressjs.At first, you have to run npm install cors -force.Then add the code that is given bellow:-
const cors=require('cors')
app.use(cors({origin:true}))
I'm calling a service from my api built with sinatra, and I make a simple ajax call as I mention it below:
<script>
$(document).ready(function (){
seeStatus()
});
function seeStatus(){
token = $('#token').val();
$.ajax({
url: '/see/v1/status/' + token,
type: 'GET',
dataType: "script",
complete: function (response) {
var json = $.parseJSON(response.responseText);
if (json.error == 0) {
window.location.href = json.href
}
}
});
}
</script>
made a GET call and the server receives a call OPTIONS
190.141.191.102 - - [08/Mar/2018:12:31:38 +0000] "OPTIONS /see/v1/status/f4dce2eb193674cab37ff36cbaca2eb4c0355165?_=1520512306539 HTTP/1.1" 404 51 0.0133
The code of my service is not executed from the ajax method and I do not understand why? , when I try my service independently with an HTTP client it works correctly What can I do? Any help Thanks
It looks like you're having an issue with CORS (Cross-Origin Resource Sharing). It would be interesting to know where the script requesting the API and where the API itself are located. I guess they're not on the same server.
In a nutshell, CORS is a mechanism that prevents a resource on one domain to freely access a resource on another domain. Your webpage can load resource on its own domain (scripts, stylesheets, fonts, json, etc.) but by default, Javascript HTTP requests (XMLHttpRequest / fetch) use the same-origin policy by default, which means they can only request resources on the same domain.
According to the CORS dedicated page on the MDN, here's the reason for the OPTIONS request you see on the server side:
the specification mandates that browsers "preflight" the request, soliciting supported methods from the server with an HTTP OPTIONS request method"
I guess you'll have to configure CORS on your server, or make it so that the HTML file calling the API is located on the same domain as the API itself (which might not be possible).
Since you used the Sinatra tag in this question, I guess your server is written in Sinatra, in that case you can use the britg/sinatra-cross_origin gem to setup CORS rule on your API server.
EDIT:
Problem is resolved. My front end code is fine, it's error of back end guys.
I have problem when POST data cross domain. I don't know why, just 3 hours ago it worked fine. At that time I just made some changes in CSS and HTML, I was not touch to any JS file. I also asked the Back end team (They're using Ruby on Rails) and they told me that they still working on localhost.
This error appear every time I try to POST to server when using both Firefox and Chrome:
XMLHttpRequest cannot load https://time-traveler-back.herokuapp.com/api/sessions/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access. The response had HTTP status code 503.
For Chrome, I already installed CORS app. But if I turned it on, another error appear:
XMLHttpRequest cannot load https://time-traveler-back.herokuapp.com/api/sessions/login. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:9000' is therefore not allowed access.
Here is my app config:
// Config for POST data cross domain
app.config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {
$httpProvider.defaults.useXDomain = true;
$httpProvider.defaults.withCredentials = true;
delete $httpProvider.defaults.headers.common["X-Requested-With"];
$httpProvider.defaults.headers.common["Accept"] = "application/json";
$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
}]);
This is how I POST data:
var apiUrl = 'https://time-traveler-back.herokuapp.com/api/';
$http({
method: 'POST',
url: apiUrl + 'sessions/login',
data: $.param(formData), // pass in data as strings
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
} // set the headers so angular passing info as form data (not request payload)
})
.then(function successCallback(response) {
// my stuffs
}, function errorCallback(response) {
// my stuffs
});
Please help me. Thanks.
Credentials and CORS
One thing to note when using withCredentials: true in your app and
configuring the server for CORS is that you may not have your
Access-Control-Allow-Origin header set to '*'. It must be configured
to a few select origins. If you absolutely must have this set to *,
then I suggest doing something beyond cookie based authentication,
such as token-based authentication.
See AngularJS Authentication and CORS
Looks like a standard CORS error.
You already fixed, but in case of doubt, I'll give some recommendations:
Rack-CORS
If using rails as the backend, you should definitely check out the rack-cors gem. This basically sets up all the CORS policies for your server through the middleware in the most simple way possible:
#config/application.rb
...
config.middleware.insert_before 0, "Rack::Cors" do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post, :options]
end
end
This allows you to permit particular domains "origins" & methods to your app.
--
You must also remember that to prevent cross domain XML requests, "CORS" (Cross Origin Resource Sharing) was instituted to apply a "lock" on which resources / urls are accessible by JS requests.
As a rule of thumb, if you're ever using JS to automagically update the front-end with an XML request of a separate domain (not just Ajax), you'll need to permit the domain in your server's CORS policy.
There are a number of ways to do this; simplest with rails is to use the rack-CORS gem (as above).
I'm building an app that has to get and set data at a remote web service through requests. When I use the jQuery GET request it works fine, I can request data from the service without any problems, but when I use PUT I get some erros:
OPTIONS http://myurl.com 501 (Unsupported method
('OPTIONS'))
OPTIONS http://myurl.com Origin null is not allowed by Access-Control-Allow-Origin.
I've tried almost anything to get this to work, but it won't work. I've download a chrome app called REST Console, which can make custom REST requests. The strange thing is that I can interact with my server over that app but not through my javascript!
This is the javascript:
$.ajax({
url: 'http://myurl.com',
type: 'PUT',
data: '<time>16:00</time>',
success: function(data) { alert(data); }
});
Could anybody tell me what is going on here?
First ensure you're serving the page that runs the script from a web server, not directly from the file system.
I'm guessing your service at http://myurl.com is at a different host name to the host name your page is being served from? For it to work in this case you need to implement HTTP headers to support Cross Origin Resource Sharing.
Your service at http://myurl.com needs to handle an HTTP OPTIONS request, the response to which should be a set of HTTP headers (with no content) as follows:
Access-Control-Allow-Origin: http://url-of-page-with-javascript/
Optionally you can also specify Access-Control-Allow-Credentials, Access-Control-Allow-Headers and Access-Control-Allow-Methods. See the full specification here.
You'll also need to add the same headers with the same values when your server responds to the PUT request - obviously the content will also be included with this response.
I have found this very useful Chrome extension called Postman. This is a very useful extension especially when you are into programming RESTful applications.
One thing I am confused on is that how this plugin/extension able to send POST request successfully on different domains?
I tried voting in a poll using Postman like this.
After submitting that, the vote was actually counted in, but when I tried doing that using AJAX and JavaScript, it fails, because of different origin policy of browsers.
How is that even possible?
Here is my code using jQuery. I used that in my computer though, localhost.
init: function() {
$.ajax({
url: 'http://example.com/vote.php',
type:'POST',
dataType: 'html',
data: {
id: '1'
},
success: function(data) {
if ( data == 'voted' ) {
$('.set-result').html( 'you already voted. try again after 24 hours' );
} else {
$('.set-result').html( 'successfully voted' );
}
}
});
},
Chrome packaged apps can have cross domain permissions. When you install Postman it promts you that this app will access any domain.
By placing */* in permissions section of your manifest file, you can do this.
Read more here:
https://developer.chrome.com/extensions/xhr.html
You can add the following header to sent Ajax request in postman.
Content-Type application/json
X-Requested-With XMLHttpRequest
Screenshot
Sounds like the site that hosts the poll (the "vote.php" script) needs to have an "Access-Control-Allow-Origin" header set to allow posting from a list of sites (or all sites).
A value of * for the header will allow posting from any website:
Access-Control-Allow-Origin: *
i.e. You could put the following at the top of vote.php
header('Access-Control-Allow-Origin: *');
Chrome extensions and apps are not subject to the same security limitations placed on normal webpages.
Additional debugging tips:
If you're trying to access remote services from web pages you have open on your local file system in your browser, you might find your browser applies different security rules to them than it does to files served from a web service.
e.g. If you open local files from a locational like C:\MyDocuments\weboot\index.htm (Windows) or \Users\joe\Sites\index.html (Mac) in your browser your AJAX request might not work, even with the header specified in most browsers.
Apple's Safari applies almost no cross domain restrictions to files opened locally but Firefox is much more strict about what it permits, with Chrome somewhere in the middle. Running a web server locally (e.g. on http://localhost/) is a good idea to avoid unexpected behaviour.
Additionally, other libraries that provide functions to handle Ajax requests (such as AngularJS) may require other headers to be set on the server by default. You can usually see the reason for failure in a browser debug console.
2021 Oct
In my investigation, I found out that you need an extra field in the header of your request. So simply add the following key-value into the header:
key: X-Requested-With | value: XMLHttpRequest