GWT上的RESTlet无法检索未由启用GWT的服务器支持的RESTful资源

时间:2013-03-30 16:23:03

标签: rest gwt restlet

我正在尝试让GWT + RESTlet与RESTful服务进行通信,而不是“GWT感知”。

在GWT客户端上,我执行类似

的操作
Reference ref = new Reference("http://localhost:8080/control/programs/");
ProgramListResourceProxy clientResource = GWT.create( ProgramListResourceProxy.class );
clientResource.setReference( proxyRef );
clientResource.setFollowingRedirects( true );
clientResource.accept( MediaType.APPLICATION_JSON  );
clientResource.accept( MediaType.APPLICATION_XML  );

ProgramListResourceProxy resource = RestClient.createProgramListResource();
resource.retrieve( new Result<ArrayList<ProgramRef>>()
{
    @Override
    public void onFailure( Throwable caught )
    {
        while( caught != null)
        {
            Window.alert( "Error retrieving programs.\n" + caught.getMessage() );
            caught = caught.getCause();
        }
    }

    @Override
    public void onSuccess( ArrayList<ProgramRef> result )
    {
        Window.alert( "Programs: " + result );
        programs = result;
        view.setRowData( toStringList( result ) );
    }
});

如果我从浏览器请求资源,我会

[{"name":"niclas","link":{"action":"GET","path":"/control/programs/niclas/"}}]

正如所料。

但是当在GWT中执行上面的代码时,我得到弹出警告告诉我存在问题,并且在嵌套异常中是;

Error retrieving programs.
Can't parse the enclosed entity because of its media type. 
Expected <application/x-java-serialized-object+gwt> but was 
<application/json>. Make sure you have added the 
org.restlet.client.ext.gwt.jar file to your server.

MediaTypes在请求/响应中匹配,流量如下所示。

请求;

GET /control/programs/ HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Accept: application/json, application/xml
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
Referer: http://localhost:8080/connect/Connect.html
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3

响应;

HTTP/1.1 200 OK
Date: Sat, 30 Mar 2013 15:46:04 GMT
Content-Type: application/json; charset=UTF-8
Date: Sat, 30 Mar 2013 15:46:04 GMT
Accept-Ranges: bytes
Server: Restlet-Framework/2.1.2
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
Transfer-Encoding: chunked

4E
[{"name":"niclas","link":{"method":"GET","path":"/control/programs/niclas/"}}]

有人可以解释为什么Restlet期望“application / x-java-serialized-object + gwt”而不是资源中设置的MediaType吗?

是否与使用org.restlet.client.resource.ClientProxy有关?如果是这样,是否有另一种方法可以使用RESTlet执行这些异步请求?

我正在使用RESTlet 2.1.2和GWT 2.2.0。

先谢谢。

3 个答案:

答案 0 :(得分:0)

我通常使用带有覆盖类型的JsonpRequestBuilder(在本例中为JsonVideoList):

JsonpRequestBuilder builder = new JsonpRequestBuilder();
builder.requestObject(url, new AsyncCallback<JsonVideoList>() {
    @Override
    public void onFailure( Throwable exception) {
    }

    @Override
    public void onSuccess(JsonVideoList list) {
    }
});

答案 1 :(得分:0)

我发现this issue在谷歌中搜索您的问题,这可能已经连接。

以下内容可能效率不高,但您也可以查看restyGWT进行休息调用。

答案 2 :(得分:0)

当天结束时有几个问题,我认为我最好分享我的发现;

  1. 我没有意识到我有一个“同源”的问题。这是通过在我的Rest服务器的GWT服务端口上使用透明代理来解决的。这似乎也正确地将Rest服务器的身份验证转发到浏览器中的GWT应用程序。

  2. Restlet在Editions中的包装似乎是一个非常好的主意。但是让IntelliJ IDEA能够使用这些以及共享的DTO模块来设置GWT调试环境真的很困难。我认为我有其他问题有关Restlet的方法,以确定使用哪些内容类型和不使用的内容类型。当天结束时,我说服自己不要打扰共享的DTO库而是;

    • 服务器端使用Restlet的Jackson扩展,pojo类作为DTO。
    • 在GWT方面,我要求Restlet仅处理Representation类型并使用GWT中的AutoBean功能来进行序列化。 (见下文)
  3. AutoBean很棒;

    public interface Program
    {
        String getName();
    
        void setName( String name );
    
        List<Block> getBlocks();
        void setBlocks(List<Block> blocks);
    
        List<Connection> getConnections();
        void setConnections(List<Connection> connections );
    
        public static class Factory
        {
            public static Program make() {
                AutoBean<Program> ref = ModelFactory.instance.program();
                return ref.as();
            }
    
            public static String toJson(Program ref) {
                AutoBean<Program> bean = AutoBeanUtils.getAutoBean( ref );
                return AutoBeanCodex.encode( bean ).getPayload();
            }
    
            public static Program fromJson(String json) {
                AutoBean<Program> bean = AutoBeanCodex.decode( ModelFactory.instance, Program.class, json );
                return bean.as();
            }
        }
    }
    

    为了使样本完整,我的ModelFactory有这些的创建方法,这些方法也由GWT完全处理;

    public interface ModelFactory extends AutoBeanFactory
    {
        ModelFactory instance = GWT.create( ModelFactory.class );
        AutoBean<Program> program();
        AutoBean<ProgramRefList> programRefList();
        :
    }
    

    一个不明显的问题是如何处理顶级JSON列表,因为AutoBean将JSON键与接口中的字段匹配。但我找到了一个巧妙的小技巧,可以在同一个程序的以下片段中看到;

    public interface ProgramRefList
    {
        List<ProgramRef> getList();
    
        public static class Factory
        {
            public static ProgramRefList make()
            {
                AutoBean<ProgramRefList> ref = ModelFactory.instance.programRefList();
                return ref.as();
            }
    
            public static String toJson( ProgramRefList ref )
            {
                AutoBean<ProgramRefList> bean = AutoBeanUtils.getAutoBean( ref );
                return AutoBeanCodex.encode( bean ).getPayload();
            }
    
            public static ProgramRefList fromJson( String json )
            {
                json = "{ \"list\": " + json + "}";
                AutoBean<ProgramRefList> bean = AutoBeanCodex.decode( ModelFactory.instance, ProgramRefList.class, json );
                return bean.as();
            }
        }
    }
    

    顶级列表伪造成另一个具有单个键的对象(在本例中为“list”),然后可以从getList()方法访问它。

    然后在Rest客户端代码中使用它非常简单;

        ClientResource resource = RestClient.createProgramList( new Uniform()
        {
            @Override
            public void handle( Request request, Response response )
            {
                Logger.trace( this, "handle(" + request + "," + response + ")" );
                try
                {
                    if( response.isEntityAvailable() )
                    {
                        String jsonText = response.getEntity().getText();
                        programs = ProgramRefList.Factory.fromJson( jsonText );
                        ArrayList<String> rowData = toStringList( programs );
                        view.setRowData( rowData );
                    }
                }
                catch( Exception e )
                {
                    Logger.handleException( this, "loadProgramsList()", e );
                }
            }
        } );
        resource.get();