Showing posts with label cors. Show all posts
Showing posts with label cors. Show all posts

Tuesday, March 24, 2015

Spring boot and CORS (Cross Origin Resource Sharing)

Another example of use - spring boot

Sometimes a web application needs access to local resources (filesystem, printers, devices, etc).
The access is possible through Java Applets, ActiveX, browser plugins or ... a client application exposing REST API and the web application called by the client application through the Cross Domain AJAX call. This post describes how  you can create a local microserver called by browser in (about) 5 lines of code with spring boot.

The creation of a microserver with spring boot is very easy. Simply annotate your class with @RestController and your methods with @RequestMapper.  That's it.

But when the browser calls the local mircoserver as it follows:

$.ajax({
url: 'http://localhost:8080/rest/printers',
type: 'GET',
dataType: 'json',
async: true,
cache: false,
crossDomain: true,
beforeSend: function (xhr, opts) {
var auth = make_base_auth(user, password);
console.log('auth:' + auth);
xhr.setRequestHeader('Authorization', auth);
},
success: function (resp) {
$('#result').text(resp);
},
error: function(xhr) {
alert('Error!  Status = ' + xhr.status + " Message = " + xhr.statusText);
}
});

The browser raises this exception:

XMLHttpRequest cannot load http://localhost:8080/rest/printers?_=1424781952941. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access.

In fact,  when you call the external domain the browser checks your call and it runs the CORS protocol http://www.w3.org/wiki/CORS for more details.

how can you work it out?

You can use a cors-filter  adds this dependence and registers the filter

@Bean
public FilterRegistrationBean corsFilter() {
FilterRegistrationBean registrationBean =
new FilterRegistrationBean();
CORSFilter corsFilter = new CORSFilter();
Map<String, String> params = new HashMap<>();
params.put("cors.allowed.methods",CORSFilter.DEFAULT_ALLOWED_HTTP_METHODS + ",DELETE,PUT");
params.put("cors.allowed.headers",CORSFilter.DEFAULT_ALLOWED_HTTP_HEADERS + ",authorization");
params.put("cors.logging.enabled", "true");
registrationBean.setInitParameters(params);
registrationBean.setFilter(corsFilter);
registrationBean.setUrlPatterns(Arrays.asList("/rest/*"));
return registrationBean;
}

at this point when the browser calls the external domain, the local microserver allows this call and it works.


Consideration for IE8-9

In this type of browser CORS is supported by XDomainRequest, not by XMLHttpRequest. 
This means that you need a jquery plugin jQuery-ajaxTransport-XDomainRequest to make a Cross Domain AJAX call.

IE 8-9 has more limitations. See xdomainrequest-restrictions-limitations-and-workarounds for more details and remember you must enable cross domain in security options!

To by-pass IE8-9 limitations you can add a workaround filter to microserver

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public FilterRegistrationBean createIE8_9XDomainRequestFilter() {
    FilterRegistrationBean registrationBean =
            new FilterRegistrationBean();
    registrationBean.setFilter(new IE8_9XDomainRequestFilter());
    registrationBean.setUrlPatterns(Arrays.asList("/rest/*"));
    return registrationBean;
}


source code