本地HTML访问REST服务的实现

本地HTML访问REST服务的实现

 

1     前言

最近一段时间在研究如何实现跨平台应用,其中的一个关键技术点就是本地HTML页面如何访问远程服务。经过探索,终于解决了碰到的各种问题,做出了一个Demo. 

本文就Demo所用的技术架构做了一个简介,并分析了实现中碰到的问题及相应的解决方法。一来以此作为这段时间工作的一个技术总结,二来希望能对其他同行有所帮助。

2         技术架构

Demo 本身的功能很简单,

1)      本地HTML 发出 “POST” 命令,发送一段数据到 Server端

2)      Server 端存储收到的数据

3)      本地HTML  发出工“GET” 命令,取回数据  

Demo分为两部分。Client端比较简单,就是HTML+JQuery.  Server端则用REST服务, 是用JAVA写的,具体方案是glasshfish+ Jersey.  两者这间用Json格式通信。

3         主要问题的解决方法:

3.1       Same origin policy

3.1.1       问题

这是整个Demo中耗时最多的一个问题。问题的表象是 从Chrome发出HTTP命令后,Chrome console中报 “Origin null is not allowed by Access-Control-Allow-Origin”错误。

这是由于Browser的same origin policy 限制的缘故。简单来说,从HTML中发出XMLHttpRequest  请求时,Browser会做检查,如果发现Response中没有Access-Control-Allow-Origin Header或Access-Control-Allow-Origin Header Header的值与 HTML的 orgin 不同时,Browser会拒接绝该Response,Javascript就收不到该Response。 本地HTML的Origin是 null, 而Server端没有发出Access-Control-Allow-Origin Header Header给Browser,  所以会有了“Origin null is not allowed by Access-Control-Allow-Origin”错误。

3.1.2       解决方法

事实上有一个W3C标准,Cross Origin Resource Sharing (CORS) 专门用来解决这个问题的。目前的主流Browser也有支持。CORS 在HTTP Message 加入几个Header, Browser和 Server可以利用这些Header来判断对方是否是安全,是否可以通信。

具体来说,CORS包括两方面。 Server端和Browser端。

3.1.2.1       Server端

以Demo中的Server端为例,解决方法就是在 Jersey Servlet中加入一个Filter, 在 Filter中修改给Browser的Response, 共有两步

1)      配置Web.xml

在Jersey Servlet中加入init-param

<servlet>

        <servlet-name>ServletAdaptor</servlet-name>

        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>

        <init-param>

              <param-name>com.sun.jersey.spi.container.ContainerResponseFilters</param-name>

             <param-value>jasontesting.ResponseCorsFilter</param-value>

        </init-param>

        <load-on-startup>1</load-on-startup>

       

</servlet>

 

2)      ResponseCorsFilter

/*

 * To change this template, choose Tools | Templates

 * and open the template in the editor.

 */

package jasontesting;

 

/**

 *

 * @author jianl

 */

import javax.ws.rs.core.Response;

import javax.ws.rs.core.Response.ResponseBuilder;

 

import com.sun.jersey.spi.container.ContainerRequest;

import com.sun.jersey.spi.container.ContainerResponse;

import com.sun.jersey.spi.container.ContainerResponseFilter;

 

public class ResponseCorsFilter implements ContainerResponseFilter {

 

    @Override

    public ContainerResponse filter(ContainerRequest req, ContainerResponse contResp) {

 

        ResponseBuilder resp = Response.fromResponse(contResp.getResponse());

        resp.header("Access-Control-Allow-Origin", "*")

                .header("Access-Control-Max-Age", 1728000)

        .header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");

 

        String reqHead = req.getHeaderValue("Access-Control-Request-Headers");

 

        if(null != reqHead && !reqHead.equals(null)){

            resp.header("Access-Control-Allow-Headers", reqHead);

        }

 

        contResp.setResponse(resp.build());

            return contResp;

    }

 

}

3.1.2.2       Browser端

如前所述,Browser已经实现了CORS,CORS对应用开发人员是透明的。为了方便,公布Demo的Browser端源代码如下。

<script src="jquery-latest.js"></script>

  <script src="jquery.json-2.3.js"></script>

<script type="text/javascript">

  var url= "http://localhost:8080/WebApplication3/resources/contact";

  var postobject={id:2,name:"Bob9",addresses:[{street:"Long Street 1",town:"Short Village"}],id_attribute:888};

 jQuery.ajax({

      url: url,

      type: "POST",

      data: $.toJSON(postobject),

      dataType: "json",

      contentType:"application/json",

      success: function(result) {

                     //Write your code here

                  //alert(result);

                  $.get(

                                                    url,

                                                    function(data, textStatus, jqXHR) {

                                                                alert(data);

                                                    },

                                                    "json"

                                                );

      }

});

  </script>

3.2       Accept and Content-Type Header

这个问题本身并不复杂,但由于之前对HTTP协议并不十分了解,还是花了大半天时间。问题核心是要在Request中要加入 Accept 与 Content-Type Header,指定可接爱的和发送的MIME 类型。具体的解决例子可参考Browser端的代码。

4          总结

经过这些天的摸索,终于做出这个Demo,弄清楚了本地HTML访问REST服务可如何实现,心中很是欣慰。要继续努力,深化在移动开发方面的技术积累。

5         参考

 

http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/

http://www.html5rocks.com/en/tutorials/cors/

http://blog.usul.org/cors-compliant-rest-api-with-jersey-and-containerresponsefilter/

posted @ 2012-04-09 22:35 LevinJ 阅读(...) 评论(...) 编辑 收藏