您的位置:首页 > 大数据 > 人工智能

Jersey (JAX-RS) implements a Cross domain filter

2014-05-26 14:27 399 查看
原文地址:http://simplapi.wordpress.com/2013/04/10/jersey-jax-rs-implements-a-cross-domain-filter/

After seeing how to create a
HTTP Basic Auth Filter, we will add this time a cross domain output filter.

Cross-Domain request is available threw
CORS system, it allow developper to send request to some domains which are not directly related to their HTML page, this is one of the great new features of new Xhr level 2 (already available in most of browsers).

It’s a pretty usefull feature in many case, here we will show a simple example how to embed a REST Web Services into an app (in pure HTML/JS), without any transfert threw a sub-resource provider/proxy.

Understanding the Jersey filter

We already see in previous article the filter for input request, here it’s the opposite : we want to add support on output filter.

Basically, Jersey allow to add any number of filter at input level, or, output level. We will use here the output filter.

Like previous article, we will describe both : Tomcat (v7), and Java built in server.

Java built-in server
ResourceConfig rc = new PackagesResourceConfig("");
rc.getProperties().put(
"com.sun.jersey.spi.container.ContainerResponseFilters",
"com.sun.jersey.api.container.filter.LoggingFilter;com.myprogram.CrossDomainFilter"
);

HttpServer server = HttpServerFactory.create("http://localhost:9999/", rc);
server.start();


Tomcat
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter;com.myprogram.CrossDomainFilter</param-value>
</init-param>

Quite the same as previous article, just the parameter now is named "ContainerResponseFilters" instead of "ContainerRequestFilters" indicate to Jersey we want this time use the output not the input. Again the "LoggingFilter" is a basic -already done- filter
provided by Jersey, allowing to get a nice debug console of input/output.

Now we put our class "com.myprogram.CrossDomainFilter" in the filter chain, we can create it.

The output filter

The output filter is a little bit different, but like input filter quite easy to understand :

/**
* Allow the system to serve xhr level 2 from all cross domain site
*
* @author Deisss (LGPLv3)
* @version 0.1
*/
public class CrossDomainFilter implements ContainerResponseFilter {
/**
* Add the cross domain data to the output if needed
*
* @param creq The container request (input)
* @param cres The container request (output)
* @return The output request with cross domain if needed
*/
@Override
public ContainerResponse filter(ContainerRequest creq, ContainerResponse cres) {
cres.getHttpHeaders().add("Access-Control-Allow-Origin", "*");
cres.getHttpHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
cres.getHttpHeaders().add("Access-Control-Allow-Credentials", "true");
cres.getHttpHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
cres.getHttpHeaders().add("Access-Control-Max-Age", "1209600");
return cres;
}
}

As you see, every parameter are in String way, in fact you can put what you want.

Here is a basic explain about thoose parameters :

Origin : indicate which url is allowed or not. The * is the wildcard parameter, you can put for example
http://localhost if you want to restrict to localhost only
Headers : you probably don’t need to change this one, it’s indicating what headers you will use. There is no wildcard for this one
Credentials : let it to true will be fine…
Methods : even if you don’t use head or options, you should let them like this : the CORS system send OPTIONS request to catch cross domain policy, if you don’t set it it will be refused
Max-Age : the max age policy to renew CORS check. Here it’s 14 days long

As you see, thoose parameters are used BY BROWSER, not your Ajax request. It means that browser will check BEFORE your request. And you can’t pass threw a wrong policy check…

Now your Jersey part should be working, let’s make a simple request to check everything is fine.

The CORS Client

I will describe here a pretty basic example using jQuery (because it’s a lot used, definitely not my favorite…). Also, you may need to setup a auth filter for that part : allowing all OPTIONS request to be throw as "HTTP OK". If you need so, use

this article. In this case, you need to escape all options, so at the beginning of the filter, add like this (see from methods.equals("OPTIONS")) :

@Override
public ContainerRequest filter(ContainerRequest containerRequest) throws WebApplicationException {
//GET, POST, PUT, DELETE, ...
String method = containerRequest.getMethod();
// myresource/get/56bCA for example
String path = containerRequest.getPath(true);
if(method.equals("OPTIONS")) {
throw new WebApplicationException(Status.OK);
}


I need to do that, i don’t remember exactly why (if I remember it was just a 404 error making the system to not validate CORS policy). This will be enough to get everything running good with any HTML page allowing CORS. Of course if you are using OPTIONS
in your application, this trick is not for you, you should adapt it !

Now on client side, you can see we send a simple, and regular AJAX request, yes, the browser is the key here, you don’t need to setup anything special, the browser will check everything instead of you :

/**
* Call the server using ajax cross domain request compatible
*
* @author Deisss (LGPLv3)
*
*
* @param path {String} The url to get
* @param type {String} GET, POST, PUT, DELETE, ...
* @param data {Object} Any data to supply
* @param success {Function} The success method called in case of success
* @param error {Function} The error method called in case of error
*/
function call(path, type, data, success, error){
var l = login,
p = password;

$.ajax({
url:            path,
data:           (data) ? JSON.stringify(data) : "",
dataType:       'json',
type:           type,
contentType:    'application/json; charset=UTF-8',
crossDomain:    true,

//Prepare the authorization request from it
beforeSend : function(xhr) {
var base = Base64.encode(l+ ":" + p);
xhr.setRequestHeader("Authorization", "Basic " + base);
},

//Handle default error check
statusCode: {
400 : function(){
alert('400 : bad request');
},
401 : function(){
alert('401 : unauthorized');
},
403 : function(){
alert('403 : forbidden');
},
404 : function(){
alert('404 : not found');
},
415 : function(){
alert('415 : type not allowed');
},
500 : function(){
alert('500 : internal server error');
}
},

//Callback
success:        (success) ? success : null,
error:          (error) ? error : null
});
};
As you see… Nothing to do ! The cross domain is in fact used by the browser directly, the browser is the one which is taking care of policy. You just need to do regular ajax request. Here I also add the HTTP Basic Auth from previous article
(so you can see how to do cross domain with Basic Auth).

From this example : don’t forget to use HTTPS in all case, because the HTTP Auth is not encrypted at all, so you should take care a lot about that…

Final Words

You are now ready to interact with Web Services threw HTML page directly, allowing to build your system faster by interacting directly with many of your Web Services !
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: