Джейсон размышлял над тем, как заставить Javascript общаться с PHP или, другими словами, как заставить веб-страницу загружать данные без перезагрузки (или, по крайней мере, без перезагрузки).
Зачем это делать? Потому что вы можете создать впечатление расширенного клиента (настольного графического интерфейса пользователя) по сравнению с типичным тонким клиентом на основе Интернета, где простое взаимодействие с пользователем часто требует значительных перезагрузок страницы и ожидания.
В качестве примера рассмотрим простое веб-приложение для администрирования, где администратор имеет список пользователей и может редактировать каждого пользователя в списке. Как мы можем избежать перезагрузки списка пользователей между каждым редактированием для одного пользователя?
На первый взгляд, решить эту простую проблему — или, может быть, это простая задача, которую нужно решить. Посмотрите немного дальше, и вы обнаружите, что это одна из тех серых областей веб-разработки, которая заставляет вас задуматься: «Это 2004 год. Кто-то, должно быть, уже решил это раз и навсегда».
В любом случае, это длинная и не особо сфокусированная напыщенная речь, которая также следует из Seperating Browser из Resource и сериализации PHP-структур данных для Javascript .
Не стесняйтесь, чтобы пламя / исправить. Миссия состоит в том, чтобы попытаться определить «проблему» как можно более полно. Возможно, это нужно перенести в WIKI в свое время.
Механизм / Полезная нагрузка / Население
Подумайте, есть три основные технические области, которые следует учитывать при размышлении о том, как заставить Javascript общаться с PHP;
— механизм, который вы используете для передачи информации между Javascript и удаленным сервером
— полезная нагрузка, которую вы на самом деле обмениваете через этот механизм
— как вы заполняете пользовательский интерфейс полученной полезной нагрузкой
Обратите внимание, что я намеренно избегал таких слов, как «транспорт» и «протокол», потому что я думаю, что они затеняют проблему, особенно когда имеешь дело с такими вещами, как XML-RPC, которые равносильны протоколу, сидящему в протоколе.
Механизм
Сначала короткое слово о терминологии;
Синхронные и асинхронные вызовы
В контексте этой темы, когда вы вызываете какую-то функцию в Javascript, которая инструктирует браузер извлечь что-то с удаленного сервера, выполняет ли код, который выполнил вызов, ожидание возврата функции (синхронный вызов) или может выполнить продолжить, позволяя функции выполняться в фоновом режиме (асинхронный вызов)?
С точки зрения конечного пользователя, когда он нажимает на эту кнопку «Получить данные», пользовательский интерфейс останавливается до завершения операции извлечения данных (что будет в случае синхронного вызова), или они могут продолжать возиться в то время как браузер занят загрузкой данных с удаленного сервера (асинхронный)?
Дополнительное примечание — связано с этим в понятии блокирующих или неблокирующих сокетов . Смотрите также stream_set_blocking () в PHP.
Доступные механизмы
Учитывая варианты, которые вам нужны, чтобы Javascript взаимодействовал с удаленным сервером, реалистично (т.е. игнорируя такие вещи, как реализация SOAP в Mozilla ), кажется, что он сводится к одному из двух вариантов;
— Трюки с атрибутами HTML src
При наличии тега, который ссылается на внешний ресурс и может возвращать что-то для анализа, вы можете изменить атрибут src с помощью Javascript, позволяя главной странице оставаться резидентной в браузере.
Наиболее распространенный способ сделать это — с помощью фрейма или фрейма — см. Удаленные сценарии с IFRAME (как первая очевидная ссылка от Google).
Другой подход заключается в изменении атрибута src тега сценария, что хорошо иллюстрируется Javascript Serializer , библиотекой для взаимодействия PHP и Javascript, что подразумевает загрузку исполняемого Javascript с удаленного сервера.
В общем, я думаю, что это, пожалуй, самый разумный механизм: если вы хотите что-то, вы можете сделать работу быстро, с минимальным «риском». Это, по сути, «неуклюжий», хотя, IMO. У вас мало средств для выявления и обработки ошибок, таких как отключение удаленного сервера во время выполнения запроса, а также встраивание в ваш HTML такого содержимого, которого на самом деле не должно быть (и вы просто ждете, пока кто-то сломается). это при изменении страницы). Вы также вынуждены выполнять асинхронные вызовы, что не является катастрофой, но иногда вы хотите, чтобы ваше приложение заставляло пользователя ждать, пока ответ на действие не будет завершен.
— XMLHttpRequest
XMLHttpRequest , доступный с более или менее похожими API в последних версиях Mozilla / Firefox, IE и Safari, предоставляет вам объект Javascript, который можно рассматривать как HTTP-клиент.
XMLHttpRequest дает вам большой контроль, позволяя вашему коду быть в курсе ответов сервера (например, 404) для обработки ошибок, а также обеспечивая синхронный и асинхронный режимы, например (пример Mozilla);
var XmlHttp = new XMLHttpRequest();
// Async — выполнение продолжается после этого
XmlHttp.open (‘GET’, ‘http: //localhost/slowscript.php’, true);
// Синхронизация — выполнение ожидает завершения HTTP-запроса
XmlHttp.open (‘GET’, ‘http: //localhost/slowscript.php’, false);
Нет необходимости вставлять сомнительные теги в ваш HTML
Очевидным аргументом против XMLHttpRequest являются браузеры, которые его не поддерживают, но, как и в случае с Джейсоном, тип приложения, для которого требуется поведение расширенного клиента, часто развертывается в известной группе пользователей (например, в приложении для интрасети), где вы можете обоснованно спрос они получают с программой. В противном случае документация и опыт работы с XMLHttpRequest по-прежнему относительно скудны (но улучшаются) — если вы не уверены в Javascript, это может быть проблемой.
полезная нагрузка
Следующий вопрос: чем вы на самом деле обмениваетесь? Большая часть дискуссии была проработана с SOAP и идеями RPC против REST и закодирована против буквального. Избегая долгих обсуждений семантики, варианты выбора выглядели примерно так;
RPC vs. REST
— RPC (удаленные вызовы процедур)
Подходит программистам; вместо того, чтобы использовать какую-то библиотеку локально, вы знаете сетевой адрес этой библиотеки и вызываете ее удаленно.
Для сети «сетевой адрес», как правило, означает один URL-адрес, данные обмениваются с использованием метода HTTP POST.
Чтобы увидеть веб-RPC в его самом простом смысле (избегая затуманивания проблемы с XML), взгляните на MIME-RPC , в частности на примеры (см. Учебное пособие Kev по расширенной электронной почте в PHP как отправную точку для понимания MIME плюс сканирование по методам GET и POST в формах HTML — какая разница? если вы не уверены).
С точки зрения PHP у вас может быть такой URL;
http://www.site.com/rpc-server.php
В Javascript вы должны размещать материал по этому URL (либо используя форму, скрытую во фрейме, как предлагает Джейсон, либо с помощью XMLHttpRequest).
Простейшее представление о проблемах с веб-RPC: «Можете ли вы взаимодействовать с сервером, используя только браузер?» (Легко отлаживать?). Подразумевается, что описанный выше механизм на основе src не будет работать, поскольку он ограничен только запросами на основе GET.
— ОСТАЛЬНЫЕ
«Способ REST» (см. Здесь для хорошего резюме), по сути, отдает предпочтение методу HTTP GET.
Другими словами, должна быть возможность просматривать ваш удаленный сервер с помощью браузера, например, http://www.tekool.net/php/js_serializer/exemple_calculator.php?1,+,1 — вы можете изменить URL-адрес вручную.
REST прекрасно подходит для подхода, основанного на атрибутах src, и, как правило, его легко отлаживать. Если ваш сервер генерирует что-то вроде XML, его также легко использовать повторно для различных типов операций (например, добавьте XSLT).
Проблема (или место, где нужно принимать умные решения) заключается в том, как вы сопоставляете вызов функции (плюс ее аргументы) в Javascript с заданным URL-адресом. А как насчет отправки сложной (или большой) структуры данных, например, многомерного массива, на сервер (вам, вероятно, понадобится POST на данном этапе).
Кодированный против буквального
Следующий вопрос — в какой форме должны обмениваться данные? И будет ли запрос содержать данные в той же форме, что и ответ?
— закодировано
Кодирование данных означает представление собственных переменных (в Javascript или PHP) в некоторой промежуточной форме, понятной как клиенту, так и серверу. XML-RPC — это хорошо известный подход к кодированию как клиентских запросов, так и ответов сервера в формате XML, который описывает типы данных непосредственно, например, ответ сервера;
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
12 Egypt 0 -31
… Может соответствовать следующему в PHP;
$response = array ( 12, "Egypt", false, -31, );
… и в Javascript;
var response = [ 12, "Egypt", false, -31 ];
XML-RPC также в значительной степени решает, что вы собираетесь использовать RPC (вместо REST), но все еще представляет один из «самых разумных» подходов, учитывая многочисленные и зрелые реализации в PHP и Javascript (см. Список ниже).
Существуют альтернативные способы кодирования данных, включая кодирование WDDX и SOAP . WDDX — это, пожалуй, самый разумный путь после XML-RPC при рассмотрении PHP и Javascript ( расширение PHP WDDX и реализация Javascript ).
Вы также можете закодировать запрос другим способом по отношению к ответу, возможно, используя URL-кодировку (переменные в строке запроса GET) для запроса, даже генерируя Javascript для ответа.
Кроме того, хорошим трюком для PHP (я думаю) для работы с более сложными типами данных в клиентском запросе является сериализация в переменных Javascript в строку, готовую для функции unserialize () PHP (см. Растущие заметки, добавленные пользователем, плюс моя попытка здесь). ).
Между тем, ответ может содержать буквальный Javascript, готовый для eval () — моя попытка генератора кода для этого здесь, в то время как Javascript Serializer имеет более простую реализацию.
Основная проблема с кодированием заключается в том, что при переводе между собственными данными и закодированными данными вы можете потерять равновесие как с точки зрения разработки, так и с точки зрения производительности.
— буквальный
Под буквальным подходом подразумевается перемещение информации без самой информации , содержащей описание того, как она переводится на типы данных на родном языке. У вас может быть что-то дополнительное, например, документ схемы XML, в котором описывается, как документ должен быть «переведен», но вам решать, используете ли вы его.
Возможно, наиболее известной формой этого является сервис XML Amazon. Если рассматривать URL-адрес, подобный этому , он содержит информацию о том, на что следует переводить документ на выбранном вами языке / платформе. Тем не менее, довольно ясно, что это;
Будет выглядеть примерно так в PHP;
$catalog = array ( 'keyword' => 'php', 'product_group' => 'books', 'products' => array ( array ( 'title'=>'PHP and MySQL for Dynamic Web Sites', 'asin'=>'0321186486', 'author'=>'Ullman, Larry', ), array ( 'title'=>'PHP and MySQL Web Development', 'asin'=>'067232525X', 'author'=>'Welling, Luke', ), ), );
Это прекрасно согласуется с чем-то вроде PEAR :: XML_Serializer , как я уже упоминал ранее. К сожалению, в Javascript еще не найдено готового к применению эквивалента XML_Serializer (хотя написать его будет не сложно). Мы хотим накладных расходов на анализ XML?
Другой, очень буквальный подход — это то, что Кристиан Стокер сделал с LiveSearch , а выводом является фрагмент HTML, который вы можете вставить прямо на страницу. До сих пор никто не задавал вопросов, таких как «где же учение?»;)
Одна общая проблема (или ключевой момент принятия решения) заключается в том, как клиентские запросы должны отправляться — например, как клиент запрашивает все книги из трех разных категорий — должны ли запросы кодироваться, когда ответы являются буквальными?
Кроме того, особенно если разработчики на стороне сервера работают независимо (удаленно) от тех, кто строит клиенты, как они согласовывают общий формат? И легко ли разобрать? Все радости формирования экрана …
Население
Как только мы добрались до того, что получили что-то от сервера, что бы это ни было, следующий вопрос — как «смешать» это с пользовательским интерфейсом?
Похоже, что выбор делается между манипуляциями с DOM, XSLT или несколько хитрыми (но, вероятно, более легкими для взлома) визуальными фокусами с фреймами.
GMail, похоже, ушел на потом, используя фреймы (у меня нет аккаунта, поэтому я догадываюсь из того, что здесь говорит Марк Пилигрим). Другими словами, на стороне клиента нет никаких усилий — ответ доставляется в готовом для просмотра виде.
XSLT может быть более подходящим способом. Тогда снова…
Или, используя DOM, вы можете манипулировать всем, что вам нравится … по цене — вам нужно написать код, который заполняет эту таблицу результирующим набором, который вы только что получили с сервера. Это может быть довольно болезненным и может привести вас в сферу шаблонов (уже в зоне бедствия на стороне сервера). И жизнь становится еще интереснее, когда вы хотите что-то вроде обновления только одной строки в этом списке пользователей после редактирования одного пользователя.
Путь?
Без понятия 😉
Вероятно, самым безопасным является то, что делает GMail — давайте не будем умными. Тем не менее, считаю, что это может привести к собственным кошмарам развития. Больше об этом в другой раз.
Rant Over
Есть вторая часть этого, сосредоточенная больше на практических вопросах разработки, например, должно ли построение сервера XML-RPC в PHP выглядеть следующим образом ;
getParam(0); $x = $xval->scalarval(); $yval = $params->getParam(1); $y = $yval->scalarval();
getParam(0); $x = $xval->scalarval(); $yval = $params->getParam(1); $y = $yval->scalarval();
// Построить наш ответ.
$ struct = array (
‘sum’ => new xmlrpcval ($ x + $ y, ‘int’),
‘разность’ => новый xmlrpcval ($ x — $ y, ‘int’)
);
$ return_val = & new xmlrpcval ($ struct, ‘struct’);
return new xmlrpcresp ($ return_val);
}
новый xmlrpc_server (
массив (
‘sample.sumAndDifference’ => array (
‘function’ => ‘sumAndDifference’
)
)
);
?>
или как это;
$x + $y, 'difference' => $x - $y, ); }
$x + $y, 'difference' => $x - $y, ); }
$ server = new IXR_Server (
массив (
‘sample.sumAndDifference’ => ‘sumAndDifference’,
),
);
>>
Другой момент — насколько легко сломать клиентскую часть, когда серверная часть изменяется? Что можно сделать с помощью сгенерированного Javascript?
XML-RPC в PHP и Javascript
Выбор несколько;
— PHP
+ XML-RPC — вечно экспериментальное расширение. Хорошо, если вы скомпилировали его на своем сервере, хотя с ним трудно работать, когда дело доходит до самоанализа и неудобно использовать с классами, определенными в PHP.
+ Incutio XML-RPC — отличная библиотека от Саймона . Саймон разочаровался в этом. Тем временем я медленно взламываю (теперь немного раздутую) вилку здесь . Примечание. Я настоятельно рекомендую разобрать Incutio XML-RPC и посмотреть, как он работает.
+ PEAR :: XML-RPC — отслеживает его корни до оригинальной библиотеки полезных ссылок . Лично не большой поклонник (например, считать глобалы). Если вы используете его, убедитесь, что вы узнали, что делает функция XML_RPC_encode ().
+ Реализация XML-RPC Кейта — она не становится более простой.
— JavaScript
+ JavaScript o lait — подготовлен для использования с XMLHttpRequest. Не пробовал, но код выглядит хорошо, и это делает это возможным. Становится довольно большим, но также активно развивающимся.
+ Построитель сообщений XML-RPC Скотта Эндрю — дает вам сообщения XML-RPC — в зависимости от того, какой механизм вы используете. Легкий, что приятно.
+ vcXMLRPC — довольно полная реализация, хотя разработка сейчас мертва.
+ nsXmlRpcClient — Mozilla только через XMLHttpRequest — следите за разрешением минного поля ( см. здесь ).