3

TL/DR: How to load an XML response via FormPanel reliably?


We have a web application in GWT using Sencha GXT for most of the UI. We use a GXT FormPanel to upload a file to a server-side script (which just echoes the file's contents) to get a local file's contents in JS. Eventually this can be done with FileReader, but obviously not in browsers that don't support that.

The FormPanel submits its form and loads the result in a hidden IFrame from which the contents are extracted with the following snippet (from 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;
}

We're loading an XML file that way and the problematic line is

return iframe.contentWindow.document.body.innerHTML;

because the XML is loaded as XML (and thus not embedded in a HTML wrapper) in a few cases. I tried the following:

  1. I used Content-Type: text/html originally (oversight in the local PHP test script, error on my part in the production code). Worked in Firefox and Chrome but not in IE (9) where the XML was loaded as XML in the IFrame instead.
  2. Content-Type: application/xml which would be the correct one for the payload. Now it doesn't work anywhere because we now get the behaviour that originally only IE exhibited in Chrome and FF too.
  3. Content-Type: application/octet-stream: Not a good idea, it just downloads the file.
  4. Content-Type: text/plain: I was hoping this would always trigger the HTML/body wrapping and it does, but it also wraps everything in a pre element so it now fails everywhere, but that at least reliably. Great.

After a little digging I found out that apparently the GXT FormPanel uses the same FormPanelImpl from GWT so results are identical for both anyway. And GWT's documentation says (which Sencha wisely withheld):

The back-end server is expected to respond with a content-type of 'text/html', meaning that the text returned will be treated as HTML. If any other content-type is specified by the server, then the result html sent in the onFormSubmit event will be unpredictable across browsers, and the FormHandler.onSubmitComplete(FormSubmitCompleteEvent) event may not fire at all.

However, even with sending text/html the behaviour is unpredictable across browsers if the payload is XML.

Is there a general solution to this? Or am I missing something terribly trivial (I'm looking at GWT for just three days now)?

EDIT: I tried prepending <html><body> to the file contents so even IE would have a body in the IFrame. Well, it did, but it also resulted in a very, very strange innerHTML starting with:

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

which the XML parser understandably chokes on.

4

2 回答 2

1

My guess is that in general, wrapping XML in an HTML context without performing any escaping of special characters doesn't work reliably. I would expect it to fail at least with an XML document like

<a>
  <b>
    <html>
    </html>
  </b>
</a>

The approach we took is to just send back a small "OK" message, and then use a separate request to get the (cached) contents from the server.

Alternatively, it would probably be possible to perform HTML encoding/decoding (or Base64, ...)

于 2012-07-03T16:23:27.293 回答
0

A workaround is to override the method getContents in the class com.google.gwt.dom.client.Element.FormPanelImpl.

The code change is to use textContent instead of 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;
  }
}-*/;

I don't know whether this is a GWT bug or not.

Jordi.

于 2012-07-19T14:34:50.813 回答