Jersey (JAX-RS) implements a Cross domain filter

原文地址: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 !





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值