导航

在GWT中使用JSONP

Posted on 2010-10-21 11:12  Kyle Lee  阅读(2305)  评论(0)    收藏  举报

一、 JSONP的原理

 

JSONP即JSON with Padding,由于浏览器同源策略的限制,XmlHttpRequest不能跨域(crossdomain)访问资源。如果想要跨域访问,我们可以通过一个技巧实现。html中的script标签可以加载跨域的Javascript的文件。举一个简单的例子

比如我们在www.example.com域名下有一个html文件,有如下片段内容:

<script type="text/javascript">
var test_abc_callback = function(params) {
alert(params.a + params.b + params.c);
}
</script>
<script src="http://www.test.com/abc.js" type="text/javascript"></script>

而http://www.test.com/a.js的内容如下

test_abc_callback({"a":1, "b": 2, "c":3});

其实第一个script定义了一个名为test_abc_callback的函数
第二个script加载跨域的js文件,在js中其实调用了test_abc_callback函数,并传递一个json格式的参数。
这样就可把跨域生成的数据{"a":1, "b": 2, "c":3}获取下来。
行了,这个就是最为简单的JSONP的例子了。

上述这个例子没有任何实际价值,现在让我们看看我们通常都是如何使用JSONP的。
1. 通常我们会有一个url根据传递参数的不同,动态生成数据,如:

http://www.test.com/add.php?a=1&b=2&c=3&callback=addabc

add.php的内容如下:

<?
$a = $_GET('a') + 1;
$b = $_GET('b') + 1;
$c = $_GET('c') + 1;

header("Content-type: text/javascript");
printf("%s({\"a\":%d, \"b\":%d, \"c\":%d})", $_GET('callback'), $a, $b, $c);
?>

 

这样就根据用户请求的参数返回其想要得到的数据。

 

二、GWT中的JSONP

GWT即Google Web Toolkit,鼎鼎大名,笔者不用过多解释。GWT中有内建(buildin)的JSONP请求组件
JsonpRequestBuilder.

可以参考JsonpRequestBuilder的JavaDoc文档获取其API的更多使用方法

这里还是结合上一节的例子做一下讲解

JsonpRequestBuilder中有个requestObject的接口,有两个参数
1. url 请求数据的url。上述例子是http://www.test.com/add.php?a=1&b=2&c=3
2. callback AsyncCallback<Object>对象,包括请求成功和失败两个接口。

requestObject这个接口发送一个JSONP的请求,并期望返回一个Javascript Object类型的结果。但GWT是Java编写的,我们可以使用JSONObject来解析Javascript Object。或者使用JavaScript overlay class(下述会做讲解和演示)

下面来看一个例子: 

public class JsonpTest implements EntryPoint {

    public void onModuleLoad() {
        String url = "http://www.test.com/add.php?a=1&b=2&c=3";
        JsonpRequestBuilder jsonp = new JsonpRequestBuilder();
        
        jsonp.requestObject(url, new AsyncCallback<Abc>() {
            public void onFailure(Throwable throwable) {
                Window.alert("Error: " + throwable);
            }
            
            public void onSuccess(Abc result) {
                Window.alert("a=" + result.a() + ", b=" + result.b() + ", c=" + result.c());
            }
        });
    }
}

 

JsonpRequestBuilder会在请求是加入参数callback=__gwt_jsonp__.I0.onSuccess。如果callback的名字以被使用,可使用setCallbackParam(String)来设置

上面代码中未定义的类就是JavaScript overlay class, 下面我们来定义它。

public class Abc extends JavaScriptObject {
    protected Abc() {
    }

    public final native int a() /*-{
        return this.a;
    }-*/;

    public final native int b() /*-{
        return this.b;
    }-*/;

    public final native int c() /*-{
        return this.c;
    }-*/;
}

可以参考JavaScript Overlay Types获取关于其更多的信息
当然JavaScript Overlay Types还提供数组的实现,可使用JsArray<T>表示数组,T是数组类型,但必须也是JavascriptObject的子类型。