I have a web application running on Spring MVC using RESTful web services. I'm trying to send a JSON to those web services from an HTML/Javascript file. Here's the Javascript:
$.ajax
(
{
type: "post",
data: JSON.stringify(data),
contentType : "application/json",
dataType: "json",
url: "http://localhost/proj/service",
success: function(data)
{
callback(data);
}
}
);
And the mapping in Spring MVC:
#RequestMapping(value = "/proj/service/", method = RequestMethod.POST)
public ModelAndView procRequest(#RequestBody String paramsJson, HttpServletResponse resp, WebRequest request_p){
resp.setStatus(HttpStatus.CREATED.value());
resp.setHeader("Location", request_p.getContextPath() + "/proj/service");
resp.addHeader("Access-Control-Allow-Origin", "*");
//Code
}
For some reason when I delete the contentType key from the ajax request it goes through, but of course it is in an incorrect format since I expect the Javascript to send me a JSON string. But for some reason if I leave the contentType key I get the following error:
XMLHttpRequest cannot load http://localhost:8080/proj/service/. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
I don't know what could possibly be causing this error since the appropiate header is there.
Thanks.
The Content-Type header triggers a CORS preflight request. You need to modify your handler to respond to an OPTIONS request with the following headers:
resp.addHeader("Access-Control-Allow-Origin", "*");
resp.addHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
resp.addHeader("Access-Control-Allow-Headers", "Content-Type");
This should send the appropriate response to the preflight request, after which the browser will issue the actual request. You can learn more about preflight requests here: http://www.html5rocks.com/en/tutorials/cors/
I do it like this:
#RequestMapping("/listActions")
public #ResponseBody List<Action> list(HttpServletRequest request, HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
List<Action> actions = new ArrayList<Action>();
actions.add(new Action(1, "Do something fantastic"));
actions.add(new Action(2, "Save the world"));
actions.add(new Action(3, "Buy beer"));
actions.add(new Action(4, "Butcher a hog"));
return actions;
}
Related
I am getting a CORS issue when trying to use POST with my API.
Access to XMLHttpRequest at 'http://localhost/finalMandatory/api/track/create.php' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
I've tried to follow some other posts that seems to have the same issue, but I'm having a hard time implementing it in my own code.
$.ajax({
url: "http://localhost/finalMandatory/api/track/create.php",
type : "POST",
contentType : 'application/json',
data : form_data,
success : function(result) {
showProducts();
},
error: function(xhr, resp, text) {
console.log(xhr, resp, text);
console.log(form_data);
}
});
I'm also using these headers in my api, which i thought would be enough to deal with CORS problems.
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
I hope someone can help me fix my issue.
I guess that the OPTION request sent to create.php is failing. Maybe because your backend code is trying to perform the action even in this case. OPTION requests should terminate only with CORS headers and an empty body. You can check this with a REST client (Postman for example).
I have a simple web api created in C# which a method that returns a string
public string Get()
{
return "Welcome Web API online";
}
I am now calling it via javascript, It successfully hit the doe however it won't return any data, it always falls to error function,
var url = "https://localhost:44381/api/accounts";
$.ajax({
type: 'GET',
dataType: 'json',
url: url,
success: function (data) {
console.log(data);
},
error: function (data) { console.log(data); }
});
Checking the console log, it shows:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:44381/api/accounts?
Please enlighten me.
When we use Ajax, angular etc to access a URL that has different origin then CORS (Cross-origin-request-sharing) needs to be handled at different origin side.
Past below code in your web api project. In Global.asax.cs file
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
My be helpful to you.It works for me.
I have such method in my controller
#Controller
#RequestMapping ("/admin/users")
public class AdminUserController {
..
#RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public #ResponseBody boolean deleteUser(#PathVariable("id") int id,
HttpServletResponse response) {
..
}
..
}
and this is ajax request
$.ajax({
url: '/admin/users/'+id,
type: 'delete',
success: function(data){
console.log(data);
},
error: function(e){
console.log(e);
}
});
When I send this request, it's fails and I get 405. When I looked at response header I saw this Allow:"GET".
Ok. I change in ajax request 'delete' to 'get' but then I get in response Allow:"DELETE" ..
What it can be?
I think that DELETE actions are not allowed by your server security configurations, and basically the header:
ALLOW: GET
is suggesting you to try a GET request instead, but since you specified
method = RequestMethod.DELETE
Spring in rejecting that GET invocation to the method.
you should change method = RequestMethod.DELETE to method = RequestMethod.GET
and issue an HTTP GET request.
Let me know if this helps.
I have a REST based web service running in my Tomcat Java EE servlet container.
I am writing a jquery client that is from another domain and is therefore using CORS. It hits the login web service, followed by another call. I originally implemented these two calls using getJSON and the calls were working fine, but I wasn't getting the JSESSIONID cookie to stay on the second call, so the web service had an unauthenticated session and threw and error.
After doing research, I ran across doing ajax withCredentials and thought that this is what I needed to do. The AJAX login call failed in preflight.
So, when I sniff the traffic to my webserver, the getJSON calls run as two gets and look fine except that the cookie doesn't come back with the second call. When I run the ajax call, it does an OPTIONS call to my server, gets a 200 status back on the client and then fails inside of jQuery for reasons I can't seem to find.
var jqxhr = jQuery.getJSON(loginUrl, {
xhrFields: {
withCredentials: true
},
crossDomain: true
})
.done(function(response) {
AgileJurySessionKey = response;
AgileJuryLoggedIn = true;
doneCallback();
})
.fail(function() {
failCallback();
});
Here is the AJAX version of the same call:
jQuery.ajax(loginUrl, {
type: "GET",
contentType: "application/json; charset=utf-8",
success: function(data, status, xhr) {
alert(data);
doneCallback;
},
error: function(jqxhr, textStatus, errorThrown) {
alert(errorThrown);
failCallback;
},
xhrFields: {
withCredentials: true
},
crossDomain: true
});
What's different between these two?
Here's the filter I put in to the web server for CORS:
/**
* This filter allows access to our web services from clients that are not on the local domain
*
* #author Xerox
*/
public class CorsFilter extends OncePerRequestFilter {
/* (non-Javadoc)
* #see org.springframework.web.filter.OncePerRequestFilter#doFilterInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)
*/
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.addHeader("Access-Control-Allow-Headers", "X-Requested-With,Origin,Content-Type,Accept,Set-Cookie");
response.addHeader("Access-Control-Max-Age", "1800");//30 min
}
filterChain.doFilter(request, response);
}
}
jQuery.getJSON(loginUrl, {
xhrFields: {
withCredentials: true
},
crossDomain: true
})
The second parameter of $.getJSON is the data you want to send, not an options object. To use those, you will need to call $.ajax directly.
getJSON isn't really a method, it's just a convenience function that is basically a shortcut for:
$.ajax({
dataType: "json",
});
So basically, $.getJSON() should behave the same as $.ajax() with the dataType set to "json"
Due to continual issues with CORS, I finally gave up on this one as intractable and worked the problem from the other end.
I used a session key coming back to track the length of the session and then re-attaching security based on this, which is how I'd designed security to work in the first place.
Let's say, I have a Tornado web server (localhost) and a web page (othermachine.com), and the latter contains javascript that needs to make cross-domain ajax calls to the Tornado server.
So I set up my Tornado as such:
class BaseHandler(tornado.web.RequestHandler):
def set_default_headers(self):
self.set_header("Access-Control-Allow-Origin", "http://www.othermachine.com")
self.set_header("Access-Control-Allow-Credentials", "true")
self.set_header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS")
self.set_header("Access-Control-Allow-Headers",
"Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, X-Requested-By, If-Modified-Since, X-File-Name, Cache-Control")
And my javascript makes a jQuery call:
$.ajax({
type: 'GET',
url: "http://localhost:8899/load/space",
data: { src: "dH8b" },
success: function(resp){
console.log("ajax response: "+resp);
},
dataType: 'json',
beforeSend: function ( xhr ) {
xhr.setRequestHeader('Content-Type', 'text/plain');
xhr.setRequestHeader('Access-Control-Request-Method', 'GET');
xhr.setRequestHeader('Access-Control-Request-Headers', 'X-Requested-With');
xhr.withCredentials = true;
}
});
But I get the lovely XMLHttpRequest cannot load http://localhost:8899/load/space?src=dH8b. Origin http://www.othermachine.com is not allowed by Access-Control-Allow-Origin error. I can't tell which side of jQuery / Tornado (or both?) am I not setting up correctly.
According to dev tools, these are the headers the jQuery request is sending:
Request Headers
Accept:*/*
Origin:http://www.othermachine.com
Referer:http://www.othermachine.com/athletes.html?src=BCYQ&msgid=6xjb
User-Agent:Mozilla/5.0 ...
If I simply make a request from my browser's url field I get a '200 OK' with this:
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, User-Agent, X-Requested-With, X-Requested-By, Cache-Control
Access-Control-Allow-Methods:GET,POST
Access-Control-Allow-Origin:http://www.othermachine.com
Content-Length:0
Content-Type:text/html; charset=UTF-8
Server:TornadoServer/2.2.1
Does that mean Tornado is doing its job? I tried to follow the advice of all the stackoverflow CORS+jQuery posts (e.g. this), to no avail. CORS in concept seems simple enough, but maybe I am fundamentally misunderstanding what is supposed to happen in a CORS transaction... please help! Thanks in advance.
Nevermind, coding too late and too long causes one to trip over things the size of typos. For the record, this is all you need for jQuery:
var data = { msgid: "dH8b" },
url = "http://localhost:8899/load" + '?' + $.param(data);
$.getJSON( url, function(resp){
console.log("ajax response: "+resp+" json="+JSON.stringify(resp));
});
And this is all you need for Tornado:
class BaseHandler(tornado.web.RequestHandler):
def set_default_headers(self):
self.set_header("Access-Control-Allow-Origin", "http://www.othermachine.com")
Using jQuery 1.7.2, Tornado 2.2.1.
try setting origin to be: othermachine.com. it should be a domain name, not a website address