【问题标题】:GWT and Sencha GXT: FormPanel result failsGWT 和 Sencha GXT:FormPanel 结果失败
【发布时间】:2012-07-19 22:34:50
【问题描述】:

TL/DR:如何可靠地通过FormPanel 加载 XML 响应?


我们在 GWT 中有一个 Web 应用程序,它使用 Sencha GXT 来处理大部分 UI。我们使用 GXT FormPanel 将文件上传到服务器端脚本(它只是回显文件的内容)以在 JS 中获取本地文件的内容。最终这可以通过 FileReader 完成,但显然不能在不支持它的浏览器中完成。

FormPanel 提交其表单并将结果加载到隐藏的 IFrame 中,使用以下 sn-p(来自 FormPanelImpl.class)从中提取内容:

try {
  // Make sure the iframe's window & document are loaded.
  if (!iframe.contentWindow || !iframe.contentWindow.document)
    return null;

  // Get the body's entire inner HTML.
  return iframe.contentWindow.document.body.innerHTML;
} catch (e) {
  return null;
}

我们正在以这种方式加载一个 XML 文件,而有问题的行是

return iframe.contentWindow.document.body.innerHTML;

因为在少数情况下 XML 会作为 XML 加载(因此不会嵌入到 HTML 包装器中)。我尝试了以下方法:

  1. 我最初使用了Content-Type: text/html(本地 PHP 测试脚本的疏忽,生产代码中的错误)。可在 Firefox 和 Chrome 中工作,但不能在 IE (9) 中工作,在 IE (9) 中,XML 被加载为 IFrame 中的 XML。
  2. Content-Type: application/xml 这对于有效载荷来说是正确的。现在它在任何地方都不起作用,因为我们现在得到了原本只有 IE 在 Chrome 和 FF 中表现出来的行为。
  3. Content-Type: application/octet-stream:不是个好主意,它只是下载文件。
  4. Content-Type: text/plain:我希望这总是会触发 HTML/body 包装并且确实如此,但它也将所有内容包装在 pre 元素中,因此它现在到处都失败,但至少可靠。太好了。

经过一番挖掘,我发现 GXT FormPanel 显然使用了来自 GWT 的相同 FormPanelImpl,因此无论如何结果都是相同的。 GWT 的文档说(Sencha 明智地隐瞒了):

后端服务器应以'text/html' 的内容类型进行响应,这意味着返回的文本将被视为 HTML。如果服务器指定了任何其他内容类型,那么在 onFormSubmit 事件中发送的结果 html 将在浏览器之间无法预测,并且 FormHandler.onSubmitComplete(FormSubmitCompleteEvent) 事件可能根本不会触发。

但是,即使发送 text/html,如果负载是 XML,跨浏览器的行为也是不可预测的。

有没有通用的解决方案?还是我错过了一些非常琐碎的事情(我现在只关注 GWT 三天)?

编辑:我尝试在文件内容前添加<html><body>,这样即使 IE 也会在 IFrame 中有正文。嗯,确实如此,但它也导致了一个非常非常奇怪的innerHTML,开头是:

<?XML:NAMESPACE PREFIX = [default] ...

XML 解析器可以理解的阻塞。

【问题讨论】:

    标签: xml gwt gxt formpanel


    【解决方案1】:

    我的猜测是,一般而言,将 XML 包装在 HTML 上下文中而不执行任何特殊字符转义的工作并不可靠。我希望它至少会在像

    这样的 XML 文档中失败
    <a>
      <b>
        <html>
        </html>
      </b>
    </a>
    

    我们采用的方法是只发回一个小的“OK”消息,然后使用单独的请求从服务器获取(缓存的)内容。

    或者,也可以执行 HTML 编码/解码(或 Base64,...)

    【讨论】:

    • 目前任何编码仍然会带来一些痛苦,原因有两个:(a) 它是 GWT,所以几乎只是没有 Java-the-standard-library 的 Java-the-language,这意味着大多数解码 Base64 的方法都赢了不要跑。并且 (b) 编码是在字节级别完成的,这需要我在之后弄清楚编码(希望是 UTF-8,但你永远不会知道)。由于GWT没有处理的规定,我仍然不知道如何处理它。至少我仍然会说这是一个 GWT 文档问题(好像还不够)。
    • @Joey:我同意,(GWT)FormPanel 文档可能在这里遗漏了一些细节(GXT 更多)。我们发现使用单独请求的许多优点:它允许更轻松地重新下载、使用下载管理器进行并行下载、提高安全性(拥有一个镜像您发送的所有内容的 servlet 可能很危险)...
    • 我现在用this answer中的方法解决了。这本质上是用 HTML 实体替换特殊字符并在客户端解码。我现在唯一的问题是 Chrome 中的随机异常,但 only 在托管模式下,但那是另一个问题 ;-)。单独下载上传的文件现在在这里重新工作太多了,我什至不知道我们是否有办法在 echo 脚本托管的地方编写文件,所以我现在排除了。
    【解决方案2】:

    一种解决方法是覆盖 com.google.gwt.dom.client.Element.FormPanelImpl 类中的方法 getContents

    代码更改是使用 textContent 代替 innerHTML

    public native String getContents(Element iframe) /*-{
      try {
        // Make sure the iframe's window & document are loaded.
        if (!iframe.contentWindow || !iframe.contentWindow.document)
          return null;
    
        // Get the body's entire inner HTML.
        return iframe.contentWindow.document.body.textContent;
      } catch (e) {
        return null;
      }
    }-*/;
    

    我不知道这是否是 GWT 错误。

    乔迪。

    【讨论】:

    • 我如何让FormPanel 使用我的派生实现?
    • 我开了一张票 code.google.com/p/google-web-toolkit/issues/detail?id=7535 但显然他们不会修复它,因为 FormPanel 的文档说它只能返回 text/html。
    • new FormPanelImpl(){ public native String getContents(com.google.gwt.dom.client.Element iframe)/*-{ JSCode }-*/; };
    猜你喜欢
    • 1970-01-01
    • 2021-03-08
    • 1970-01-01
    • 1970-01-01
    • 2015-01-02
    • 2012-02-21
    • 1970-01-01
    • 2018-12-27
    • 2013-04-22
    相关资源
    最近更新 更多