GWT и Sencha GXT: результат FormPanel не выполняется
TL/DR: как загрузить ответ XML через FormPanel
надежно?
У нас есть веб-приложение в GWT, использующее Sencha GXT для большей части пользовательского интерфейса. Мы используем GXT FormPanel
загрузить файл в сценарий на стороне сервера (который просто отображает содержимое файла), чтобы получить содержимое локального файла в JS. В конце концов это можно сделать с помощью FileReader, но, очевидно, не в браузерах, которые этого не поддерживают.
FormPanel
отправляет свою форму и загружает результат в скрытый IFrame, из которого содержимое извлекается с помощью следующего фрагмента (из 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) в некоторых случаях. Я попробовал следующее:
- я использовал
Content-Type: text/html
изначально (недосмотр в локальном тестовом скрипте PHP, ошибка с моей стороны в рабочем коде). Работал в Firefox и Chrome, но не в IE (9), где XML был загружен как XML в IFrame. Content-Type: application/xml
который был бы правильным для полезной нагрузки. Теперь это нигде не работает, потому что теперь мы получаем поведение, которое изначально было только в IE и в Chrome и FF.Content-Type: application/octet-stream
: Не очень хорошая идея, он просто загружает файл.Content-Type: text/plain
: Я надеялся, что это всегда вызовет перенос HTML/ тела, и это так, но это также оборачивает все вpre
Элемент, так что теперь он терпит неудачу везде, но это по крайней мере надежно. Отлично.
После небольшой копки я узнал, что, по-видимому, GXT FormPanel
использует то же самое FormPanelImpl
от GWT, так что результаты одинаковы для обоих в любом случае. И документация GWT гласит (что Сенча мудро воздержался):
Предполагается, что внутренний сервер ответит типом содержимого
'text/html'
Это означает, что возвращаемый текст будет рассматриваться как HTML. Если какой-либо другой тип контента указан сервером, то результат HTML отправляется вonFormSubmit
событие будет непредсказуемым во всех браузерах, аFormHandler.onSubmitComplete(FormSubmitCompleteEvent)
событие может не сработать вообще.
Впрочем, даже с отправкой text/html
Поведение непредсказуемо во всех браузерах, если полезной нагрузкой является XML.
Есть ли общее решение для этого? Или я упускаю что-то ужасно тривиальное (я смотрю на GWT всего три дня)?
РЕДАКТИРОВАТЬ: я пытался предварения <html><body>
к содержимому файла, так что даже IE будет иметь тело в IFrame. Ну, это так, но это также привело к очень, очень странному innerHTML
начиная с:
<?XML:NAMESPACE PREFIX = [default] ...
который, разумеется, захлёбывает парсер XML.
2 ответа
Я предполагаю, что в общем случае упаковка XML в контекст HTML без выполнения экранирования специальных символов не работает надежно. Я ожидаю, что он потерпит неудачу по крайней мере с XML-документом, как
<a>
<b>
<html>
</html>
</b>
</a>
Подход, который мы выбрали, заключается в том, чтобы просто отправить небольшое сообщение "ОК", а затем использовать отдельный запрос для получения (кэшированного) содержимого с сервера.
В качестве альтернативы, возможно, будет возможно выполнить кодирование / декодирование HTML (или Base64, ...)
Обходной путь - переопределить метод getContents в классе com.google.gwt.dom.client.Element.FormPanelImpl.
Изменение кода заключается в использовании 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 или нет.
Jordi.