Related
I have called third party API using Jquery AJAX. I am getting following error in console:
Cross-Origin Read Blocking (CORB) blocked cross-origin response MY URL with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.
I have used following code for Ajax call :
$.ajax({
type: 'GET',
url: My Url,
contentType: 'application/json',
dataType:'jsonp',
responseType:'application/json',
xhrFields: {
withCredentials: false
},
headers: {
'Access-Control-Allow-Credentials' : true,
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'GET',
'Access-Control-Allow-Headers':'application/json',
},
success: function(data) {
console.log(data);
},
error: function(error) {
console.log("FAIL....=================");
}
});
When I checked in Fiddler, I have got the data in response but not in Ajax success method.
Please help me out.
dataType:'jsonp',
You are making a JSONP request, but the server is responding with JSON.
The browser is refusing to try to treat the JSON as JSONP because it would be a security risk. (If the browser did try to treat the JSON as JSONP then it would, at best, fail).
See this question for more details on what JSONP is. Note that is a nasty hack to work around the Same Origin Policy that was used before CORS was available. CORS is a much cleaner, safer, and more powerful solution to the problem.
It looks like you are trying to make a cross-origin request and are throwing everything you can think of at it in one massive pile of conflicting instructions.
You need to understand how the Same Origin policy works.
See this question for an in-depth guide.
Now a few notes about your code:
contentType: 'application/json',
This is ignored when you use JSONP
You are making a GET request. There is no request body to describe the type of.
This will make a cross-origin request non-simple, meaning that as well as basic CORS permissions, you also need to deal with a pre-flight.
Remove that.
dataType:'jsonp',
The server is not responding with JSONP.
Remove this. (You could make the server respond with JSONP instead, but CORS is better).
responseType:'application/json',
This is not an option supported by jQuery.ajax. Remove this.
xhrFields: {
withCredentials: false },
This is the default. Unless you are setting it to true with ajaxSetup, remove this.
headers: {
'Access-Control-Allow-Credentials' : true,
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'GET',
'Access-Control-Allow-Headers':'application/json',
},
These are response headers. They belong on the response, not the request.
This will make a cross-origin request non-simple, meaning that as well as basic CORS permissions, you also need to deal with a pre-flight.
In most cases, the blocked response should not affect the web page's behavior and the CORB error message can be safely ignored. For example, the warning may occur in cases when the body of the blocked response was empty already, or when the response was going to be delivered to a context that can't handle it (e.g., a HTML document such as a 404 error page being delivered to an tag).
https://www.chromium.org/Home/chromium-security/corb-for-developers
I had to clean my browser's cache, I was reading in this link, that, if the request get a empty response, we get this warning error. I was getting some CORS on my request, and so the response of this request got empty, All I had to do was clear the browser's cache, and the CORS got away. I was receiving CORS because the chrome had saved the PORT number on the cache, The server would just accept localhost:3010 and I was doing localhost:3002, because of the cache.
Return response with header 'Access-Control-Allow-Origin:*'
Check below code for the Php server response.
<?php header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
echo json_encode($phparray);
You have to add CORS on the server side:
If you are using nodeJS then:
First you need to install cors by using below command :
npm install cors --save
Now add the following code to your app starting file like ( app.js or server.js)
var express = require('express');
var app = express();
var cors = require('cors');
var bodyParser = require('body-parser');
//enables cors
app.use(cors({
'allowedHeaders': ['sessionId', 'Content-Type'],
'exposedHeaders': ['sessionId'],
'origin': '*',
'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'preflightContinue': false
}));
require('./router/index')(app);
It's not clear from the question, but assuming this is something happening on a development or test client, and given that you are already using Fiddler you can have Fiddler respond with an allow response:
Select the problem request in Fiddler
Open the AutoResponder tab
Click Add Rule and edit the rule to:
Method:OPTIONS server url here, e.g. Method:OPTIONS http://localhost
*CORSPreflightAllow
Check Unmatched requests passthrough
Check Enable Rules
A couple notes:
Obviously this is only a solution for development/testing where it isn't possible/practical to modify the API service
Check that any agreements you have with the third-party API provider allow you to do this
As others have noted, this is part of how CORS works, and eventually the header will need to be set on the API server. If you control that server, you can set the headers yourself. In this case since it is a third party service, I can only assume they have some mechanism via which you are able to provide them with the URL of the originating site and they will update their service accordingly to respond with the correct headers.
If you are working on localhost, try this, this one the only extension and method that worked for me (Angular, only javascript, no php)
https://chrome.google.com/webstore/detail/moesif-orign-cors-changer/digfbfaphojjndkpccljibejjbppifbc/related?hl=en
In a Chrome extension, you can use
chrome.webRequest.onHeadersReceived.addListener
to rewrite the server response headers. You can either replace an existing header or add an additional header. This is the header you want:
Access-Control-Allow-Origin: *
https://developers.chrome.com/extensions/webRequest#event-onHeadersReceived
I was stuck on CORB issues, and this fixed it for me.
have you tried changing the dataType in your ajax request from jsonp to json? that fixed it in my case.
There is an edge case worth mentioning in this context: Chrome (some versions, at least) checks CORS preflights using the algorithm set up for CORB. IMO, this is a bit silly because preflights don't seem to affect the CORB threat model, and CORB seems designed to be orthogonal to CORS. Also, the body of a CORS preflight is not accessible, so there is no negative consequence just an irritating warning.
Anyway, check that your CORS preflight responses (OPTIONS method responses) don't have a body (204). An empty 200 with content type application/octet-stream and length zero worked well here too.
You can confirm if this is the case you are hitting by counting CORB warnings vs. OPTIONS responses with a message body.
It seems that this warning occured when sending an empty response with a 200.
This configuration in my .htaccess display the warning on Chrome:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST,GET,HEAD,OPTIONS,PUT,DELETE"
Header always set Access-Control-Allow-Headers "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, Authorization"
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]
But changing the last line to
RewriteRule .* / [R=204,L]
resolve the issue!
I have a similar problem. My case is because the contentType of server response is application/json, rather than text/javascript.
So, I solve it from my server (spring mvc):
// http://127.0.0.1:8080/jsonp/test?callback=json_123456
#GetMapping(value = "/test")
public void testJsonp(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
#RequestParam(value = "callback", required = false) String callback) throws IOException {
JSONObject json = new JSONObject();
json.put("a", 1);
json.put("b", "test");
String dataString = json.toJSONString();
if (StringUtils.isBlank(callback)) {
httpServletResponse.setContentType("application/json; charset=UTF-8");
httpServletResponse.getWriter().print(dataString);
} else {
// important: contentType must be text/javascript
httpServletResponse.setContentType("text/javascript; charset=UTF-8");
dataString = callback + "(" + dataString + ")";
httpServletResponse.getWriter().print(dataString);
}
}
Response headers are generally set on the server. Set 'Access-Control-Allow-Headers' to 'Content-Type' on server side
I had the same problem with my Chrome extension. When I tried to add to my manifest "content_scripts" option this part:
//{
// "matches": [ "<all_urls>" ],
// "css": [ "myStyles.css" ],
// "js": [ "test.js" ]
//}
And I remove the other part from my manifest "permissons":
"https://*/"
Only when I delete it CORB on one of my XHR reqest disappare.
Worst of all that there are few XHR reqest in my code and only one of them start to get CORB error (why CORB do not appare on other XHR I do not know; why manifest changes coused this error I do not know). That's why I inspected the entire code again and again by few hours and lost a lot of time.
I encountered this problem because the format of the jsonp response from the server is wrong. The incorrect response is as follows.
callback(["apple", "peach"])
The problem is, the object inside callback should be a correct json object, instead of a json array. So I modified some server code and changed its format:
callback({"fruit": ["apple", "peach"]})
The browser happily accepted the response after the modification.
Try to install "Moesif CORS" extension if you are facing issue in google chrome. As it is cross origin request, so chrome is not accepting a response even when the response status code is 200
How come when I go to almost any website, for example SO, if I open up the console, inject jQuery and send a cross-domain ajax request to a server I have running on my localhost, I don't get any errors as I would have expected? However, if I open up one of the webpages that I have written myself, and which is also running on my localhost (but on a different port from the one used by the server), if I try to send an ajax request from the console I get this message:
XMLHttpRequest cannot load https://localhost:10000/. Request header field My-First-Header is not allowed by Access-Control-Allow-Headers in preflight response.
The ajax request looks like:
$.ajax({
type: 'POST',
url: 'https://localhost:10000',
headers: {
"My-First-Header":"first value",
"My-Second-Header":"second value"
}
})
To be clear, my question is not about how to fix this, but rather why I am even able to make cross-domain requests from most other websites (shouldn't they be not allowed?). Do these sites have some sort of mechanism set up that automatically bypasses the restrictions?
Request headers:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie:csrftoken=lxe5MaAlb9GC5lPGQpXtSj9HvCP0QhCz; PHPSESSID=uta0nlhlh8r1uimdklmt3v3ho1
Host:localhost:10000
Referer:http://stackoverflow.com/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36
Response headers:
Content-Length:3
Content-Type:text/html
Date:Mon, 16 May 2016 06:29:03 GMT
Server:TwistedWeb/16.0.0
It seems obvious what's going on here: the browser simply handles code typed in the console differently than code run by the page itself. It makes philosophical sense that it would work that way. After all, the point of the Same-Origin Policy is to prevent XSS and CSRF attacks, and if a user opens up their console and sends cross-domain requests, they're just attacking themselves.
On the other hand, it is possible to trick users into performing XSS on themselves. If you go to Facebook and open up the console, Facebook has code that logs a warning message telling ordinary users not to paste unknown code into the console because it could be malicious. Apparently that's a problem they've seen.
This is called as CORS request.
By default all Cross Domain requests are blocked by most of the major browsers.
Most of the portals services that you are able to request cross domain does special settings in Response. If you don't provide those settings at api level then your api will be blocked for cross domain requests.
These Response settings are as follows:
Response Header Need to have access-control-allow-origin attribute.
access-control-allow-origin can specify * for every api service at global level.
access-control-allow-origin can specify specific method name for every api service separately..
I am attempting to retrieve a class (with GET) from Parse using a client key. I was able to send a successful request using Advanced Rest Client for Google Chrome; I used X-Parse-Application-Id and X-Parse-Client-Key headers.
[edit] [edit2]
Response headers (obtained from Chrome Developer Tools OPTIONS):
HTTP/1.1 200 OK
Access-Control-Allow-Headers: X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type
Access-Control-Allow-Methods: OPTIONS, POST, GET, PUT, DELETE
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 86400
Content-Type: application/json; charset=utf-8
Date: Sun, 29 Nov 2015 04:23:08 GMT
Server: nginx/1.6.0
X-Parse-Platform: G1
X-Runtime: 0.000118
Content-Length: 0
Connection: keep-alive
However, attempting to do the same in an Angular app gives me the following error:
XMLHttpRequest cannot load https://api.parse.com/1/classes/GenResources. Request header field X-Parse-Client-Key is not allowed by Access-Control-Allow-Headers in preflight response.
Parse says it supports using cross-origin resource sharing, and I was able to make the request earlier using a different client so I'm pretty sure the server isn't the issue. I wouldn't be able to modify what the response header is anyways.
Here's the code I used to form the GET request.
var ng_portal = angular.module("ngPortal", []);
ng_portal.controller("GenResourcesCtrl", ["$http", function($http) {
$http({
method: "GET",
url: PARSE_URL + "/1/classes/GenResources",
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": PARSE_APP_ID,
"X-Parse-Client-Key": PARSE_CLIENT_KEY
}
}).then(
function success(res) {
console.log(res);
},
function error(res) {
console.log(res);
}
);
}]);
You are setting custom headers in the request, which will trigger a pre-flight (OPTIONS) request. The response from that request must include a header called "access-control-allow-headers" with the value being a list of the headers you are trying to set.
See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
specifically the section on pre-flight requests.
I suggest using the browser developer tools to look at the headers of the requests and responses to see if they conform to the CORS spec. From the error message you provided, it looks like the server hosting the cross domain call you are making, does not support custom headers. If you see otherwise, please update your question with the headers and I can provide more help.
This seems to be an issue with Parse.com actually. After exactly one frustrated hour, I came across this Google Groups post
Relevant quote
From my testing, this never ( client or javascript key) worked via javascript rest interactions through the browser.
I actually created a Parse Bug on this:
https://developers.facebook.com/bugs/488204124680438
Because I thought both of those keys should work through the browser ( WITHOUT NEEDING TO USE A SDK ).
I’d suggest reading reading my bug. I still think the the correct implementation is to enable these keys to work properly with browser requests because it works if you do it outside the browser.
But alas, they don’t seem to get the issue, or don’t understand why disabling it only in the browser doesn’t make sense since you can use it on any other platform without issues. Just… Doesn’t… Make… Sense.
I instead used my JavaScript Key X-Parse-Javascript-Key (which, according to the docs as of today, only works with their JavaScript SDK) and it works fine as a drop-in replacement for X-Parse-Client-Key
I've learned how to add custom headers to Ext-JS requests from this question:
HTTP Headers with ExtJS 4 Stores
And now I am trying to deal with the issue of exception handling when the problem is a user error. This question is dealt with here:
Understanding REST: Verbs, error codes, and authentication
One of the answers suggests mapping to the closest HTTP error code but then also using a custom response header to pass exception information back to the client.
I'd strongly advise against extending the basic HTTP status codes. If you can't find one that matches your situation exactly, pick the closest one and put the error details in the response body. Also, remember that HTTP headers are extensible; your application can define all the custom headers that you like. One application that I worked on, for example, could return a 404 Not Found under multiple circumstances. Rather than making the client parse the response body for the reason, we just added a new header, X-Status-Extended, which contained our proprietary status code extensions. So you might see a response like:
HTTP/1.1 404 Not Found
X-Status-Extended: 404.3 More Specific Error Here
I like this idea a lot. But cannot figure out how, from within ExtJS I could gain access to this custom response header to extract the exception message.
Response object has a getAllResponseHeader() method that you can use to have access to all the header key-value pairs.
In Extjs you can do something like this:
Ext.Ajax.request({
url: 'www.microsoft.com',
method: 'GET',
failure: function(response){
console.log(response.getAllResponseHeaders());
}
});
This returns an instance with this info:
connection: "keep-alive"
content-encoding: "gzip"
content-type: "text/html; charset=utf-8"
date: "Thu, 13 Dec 2012 03:10:15 GMT"
server: "nginx/0.8.54"
transfer-encoding: "chunked"
vary: "Cookie"
In your case you should do the following:
failure: function(response){
var header = response.getAllResponseHeaders(),
statusEx = header['X-Status-Extended'];
if(statusEx === '404.3 More Specific Error Here'){
// do something here
}
}
Here are two pages, test.php and testserver.php.
test.php
<script src="scripts/jq.js" type="text/javascript"></script>
<script>
$(function() {
$.ajax({url:"testserver.php",
success:function() {
alert("Success");
},
error:function() {
alert("Error");
},
dataType:"json",
type:"get"
}
)})
</script>
testserver.php
<?php
$arr = array("element1",
"element2",
array("element31","element32"));
$arr['name'] = "response";
echo json_encode($arr);
?>
Now my problem: when both of these files are on the same server (either localhost or web server), it works and alert("Success") is called; If it is on different servers, meaning testserver.php on web server and test.php on localhost, its not working, and alert("Error") is executing. Even if the URL inside AJAX is changed to http://domain.example/path/to/file/testserver.php
Use JSONP.
jQuery:
$.ajax({
url:"testserver.php",
dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
success:function(json){
// do stuff with json (in this case an array)
alert("Success");
},
error:function(){
alert("Error");
}
});
PHP:
<?php
$arr = array("element1","element2",array("element31","element32"));
$arr['name'] = "response";
echo $_GET['callback']."(".json_encode($arr).");";
?>
The echo might be wrong, it's been a while since I've used php. In any case you need to output callbackName('jsonString') notice the quotes. jQuery will pass its own callback name, so you need to get that from the GET params.
And as Stefan Kendall posted, $.getJSON() is a shorthand method, but then you need to append 'callback=?' to the url as GET parameter (yes, value is ?, jQuery replaces this with its own generated callback method).
JSONP is a good option, but there is an easier way. You can simply set the Access-Control-Allow-Origin header on your server. Setting it to * will accept cross-domain AJAX requests from any domain. (https://developer.mozilla.org/en/http_access_control)
The method to do this will vary from language to language, of course. Here it is in Rails:
class HelloController < ApplicationController
def say_hello
headers['Access-Control-Allow-Origin'] = "*"
render text: "hello!"
end
end
In this example, the say_hello action will accept AJAX requests from any domain and return a response of "hello!".
Here is an example of the headers it might return:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "c4ca4238a0b923820dcc509a6f75849b"
X-Runtime: 0.913606
Content-Length: 6
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Thu, 01 Mar 2012 20:44:28 GMT
Connection: Keep-Alive
Easy as it is, it does have some browser limitations. See http://caniuse.com/#feat=cors.
You can control this via HTTP header by adding Access-Control-Allow-Origin. Setting it to * will accept cross-domain AJAX requests from any domain.
Using PHP it's really simple, just add the following line into the script that you want to have access outside from your domain:
header("Access-Control-Allow-Origin: *");
Don't forget to enable mod_headers module in httpd.conf.
You need to have a look at Same Origin Policy:
In computing, the same origin policy
is an important security concept for a
number of browser-side programming
languages, such as JavaScript. The
policy permits scripts running on
pages originating from the same site
to access each other's methods and
properties with no specific
restrictions, but prevents access to
most methods and properties across
pages on different sites.
For you to be able to get data, it has to be:
Same protocol and host
You need to implement JSONP to workaround it.
I had to load webpage from local disk "file:///C:/test/htmlpage.html", call "http://localhost/getxml.php" url, and do this in IE8+ and Firefox12+ browsers, use jQuery v1.7.2 lib to minimize boilerplate code. After reading dozens of articles finally figured it out. Here is my summary.
server script (.php, .jsp, ...) must return http response header Access-Control-Allow-Origin: *
before using jQuery ajax set this flag in javascript: jQuery.support.cors = true;
you may set flag once or everytime before using jQuery ajax function
now I can read .xml document in IE and Firefox. Other browsers I did not test.
response document can be plain/text, xml, json or anything else
Here is an example jQuery ajax call with some debug sysouts.
jQuery.support.cors = true;
$.ajax({
url: "http://localhost/getxml.php",
data: { "id":"doc1", "rows":"100" },
type: "GET",
timeout: 30000,
dataType: "text", // "xml", "json"
success: function(data) {
// show text reply as-is (debug)
alert(data);
// show xml field values (debug)
//alert( $(data).find("title").text() );
// loop JSON array (debug)
//var str="";
//$.each(data.items, function(i,item) {
// str += item.title + "\n";
//});
//alert(str);
},
error: function(jqXHR, textStatus, ex) {
alert(textStatus + "," + ex + "," + jqXHR.responseText);
}
});
It is true that the same-origin policy prevents JavaScript from making requests across domains, but the CORS specification allows just the sort of API access you are looking for, and is supported by the current batch of major browsers.
See how to enable cross-origin resource sharing for client and server:
http://enable-cors.org/
"Cross-Origin Resource Sharing (CORS) is a specification that enables truly open access across domain-boundaries. If you serve public content, please consider using CORS to open it up for universal JavaScript/browser access."
This is possible, but you need to use JSONP, not JSON. Stefan's link pointed you in the right direction. The jQuery AJAX page has more information on JSONP.
Remy Sharp has a detailed example using PHP.
I use Apache server, so I've used mod_proxy module. Enable modules:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
Then add:
ProxyPass /your-proxy-url/ http://service-url:serviceport/
Finally, pass proxy-url to your script.
Browser security prevents making an ajax call from a page hosted on one domain to a page hosted on a different domain; this is called the "same-origin policy".
From the Jquery docs (link):
Due to browser security restrictions, most "Ajax" requests are subject to the same origin policy; the request can not successfully retrieve data from a different domain, subdomain, or protocol.
Script and JSONP requests are not subject to the same origin policy restrictions.
So I would take it that you need to use jsonp for the request. But haven't tried this myself.
There are few examples for using JSONP which include error handling.
However, please note that the error-event is not triggered when using JSONP! See: http://api.jquery.com/jQuery.ajax/ or jQuery ajax request using jsonp error
I know 3 way to resolve your problem:
First if you have access to both domains you can allow access for all other domain using :
header("Access-Control-Allow-Origin: *");
or just a domain by adding code bellow to .htaccess file:
<FilesMatch "\.(ttf|otf|eot|woff)$">
<IfModule mod_headers.c>
SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.net|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0
Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
</IfModule>
</FilesMatch>
you can have ajax request to a php file in your server and handle request to another domain using this php file.
you can use jsonp , because it doesn't need permission. for this you can read our friend #BGerrissen answer.
For Microsoft Azure, it's slightly different.
Azure has a special CORS setting that needs to be set. It's essentially the same thing behind the scenes, but simply setting the header joshuarh mentions will not work. The Azure documentation for enabling cross domain can be found here:
https://learn.microsoft.com/en-us/azure/app-service-api/app-service-api-cors-consume-javascript
I fiddled around with this for a few hours before realizing my hosting platform had this special setting.
it works, all you need:
PHP:
header('Access-Control-Allow-Origin: http://www.example.com');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
JS (jQuery ajax):
var getWBody = $.ajax({ cache: false,
url: URL,
dataType : 'json',
type: 'GET',
xhrFields: { withCredentials: true }
});
It got to work in PHP just adding this to the page served:
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
PS: I have made my own xhr suite called sa_ajax with handy and useful methods. (https://github.com/osergioabreu/sa_ajax/)