Google Web Toolkit延迟绑定问题

时间:2010-04-16 18:39:19

标签: gwt activex xmlhttprequest same-origin-policy

我在大约2年前使用GWT开发了一个Web应用程序,从那时起应用程序已经发展。在当前状态下,它依赖于获取单个XML文件并从中解析信息。总的来说,这很有效。这个应用程序的一个要求是它需要能够从文件系统(file:/// ..)以及从Web服务器(http://..运行的传统模型运行。)

使用RequestBuilder对象从Web服务器获取此文件的工作方式与预期完全相同。从文件系统Firefox,Opera,Safari和Chrome运行应用程序时,所有操作都符合预期。使用IE7或IE8从文件系统运行应用程序时,RequestBuilder.send()调用失败,有关错误的信息表明由于违反same origin policy而无法访问该文件。 该应用程序在IE6中按预期工作,但在IE7或IE8中没有。

所以我查看了RequestBuilder.java的源代码,看到实际的请求是用XMLHttpRequest GWT对象执行的。所以我查看了XMLHttpRequest.java的源代码并找到了一些信息。

这是代码(从XMLHttpRequest.java第83行开始)

  public static native XMLHttpRequest create() /*-{
    if ($wnd.XMLHttpRequest) {
      return new XMLHttpRequest();
    } else {
      try {
        return new ActiveXObject('MSXML2.XMLHTTP.3.0');
      } catch (e) {
        return new ActiveXObject("Microsoft.XMLHTTP");
      }
    }
  }-*/;

所以基本上如果无法创建XMLHttpRequest(就像IE6中那样,因为它不可用),而是使用ActiveXObject。

我更多地了解了XMLHttpRequest的IE实现,看起来它只支持与网络服务器上的文件进行交互。

我在IE8中找到了一个设置(工具 - >互联网选项 - >高级 - >安全 - >启用原生XMLHTTP支持),当我取消选中此框时我的应用程序正常工作。我认为这是因为我更不用说IE不使用他们的XmlHttpRequest实现,所以GWT只使用ActiveXObject,因为它不认为本机XmlHttpRequest可用。

这解决了这个问题,但不是一个长期的解决方案。

我当前可以捕获失败的发送请求并验证它是否正在尝试使用普通GWT从文件系统获取XML文件。在这种情况下我想做的是捕获IE7和IE8的情况并让它们使用ActiveXObject而不是本机XmlHttpRequest对象。

GWT google小组上发布了一个针对此问题的假设解决方案(link)。看着它,我可以说它是为较旧版本的GWT创建的。我正在使用最新版本并认为这或多或少是我想要做的(使用GWT deferred binding来检测特定的浏览器类型并运行我自己的XMLHttpRequest.java实现来代替内置的GWT实现)。

以下是我尝试使用的代码

package com.mycompany.myapp.client;

import com.google.gwt.xhr.client.XMLHttpRequest;

public class XMLHttpRequestIE7or8 extends XMLHttpRequest
{
    // commented out the "override" so that eclipse and the ant build script don't throw errors
    //@Override
    public static native XMLHttpRequest create()
    /*-{
        try
       {
            return new ActiveXObject('MSXML2.XMLHTTP.3.0');
       }
       catch (e)
       {
           return new ActiveXObject("Microsoft.XMLHTTP");
       }
    }-*/;

    // have an empty protected constructor so the ant build script doesn't throw errors
    // the actual XMLHttpRequest constructor is empty as well so this shouldn't cause any problems
    protected XMLHttpRequestIE7or8()
    {
    }
};

以下是我添加到模块xml中的行

<replace-with class="com.mycompany.myapp.client.XMLHttpRequestIE7or8">
    <when-type-is class="com.google.gwt.xhr.client.XMLHttpRequest"/>
    <any>
        <when-property-is name="user.agent" value="ie6" />
        <when-property-is name="user.agent" value="ie8" />
    </any>
</replace-with>

据我所知,这应该可行,但我的代码永远不会运行。

有没有人知道我做错了什么?

我不应该通过延迟绑定来执行此操作,而只是在我捕获失败案例时使用本机javascript吗?

有没有一种不同的方法可以解决我未提及过的问题?

欢迎所有回复。

2 个答案:

答案 0 :(得分:4)

您错过了一件关键的事情 - 致电GWT.create

要使deferred binding起作用,有人必须在类com.google.gwt.xhr.client.XMLHttpRequest上调用GWT.create - 只有这样才能获得特定于您需求的实现。如果查看RequestBuilder.java,它会直接实例化XMLHttpRequest对象on the first line of deSend() method。也就是说,没有调用GWT.create(),因此您的IE特定实现不会被接收。

要解决此问题,您必须替换此行

XMLHttpRequest xmlHttpRequest = XMLHttpRequest.create();

XMLHttpRequest xmlHttpRequest = GWT.create(XMLHttpRequest.class);

所以,你要么修改GWT的来源并重新编译(YUCK!),要么你做这样的事情 -

  1. 子类RequestBuilder并覆盖sendRequest()方法。
  2. 复制/粘贴doSend()方法的所有内容替换上面提到的一行
  3. 在您的代码中执行盲目操作,并将RequestBuilder的所有实例替换为MyRequestBuilder
  4. 我想这应该可以解决你的问题。

答案 1 :(得分:2)

请注意,ie7不是user.agent的有效值 - ie6是Internet Explorer 6和Internet Explorer 7的值(有关{UserAgent.gwt.xml的信息,请参阅{{3}} 1}}被计算出来。

也许这个无效的值导致GWT完全避免使用你的代码?