Оглавление | Назад | Вперёд | Индекс

Глава 5
Основы Серверного JavaScript

В этой главе даются основы серверной функциональности и различия между клиентским и серверным JavaScript. Здесь показано, как внедрять серверный JavaScript в HTML-файлы. Обсуждается, что происходит во время прогона программы на клиенте и на сервере, чтобы Вы могли разобраться во всём этом. В главе описано, как использовать JavaScript для изменения HTML-страницы, отправляемой клиенту, и, наконец, как распределить информацию между серверными и клиентскими процессами.

В главе имеются следующие разделы:

Серверный JavaScript имеет то же ядро языка, что и клиентский JavaScript, с которым Вы, возможно, уже знакомы. Задачи, выполняемые Вами при запуске JavaScript на сервере, несколько отличаются от задач, выполняемых при работе JavaScript на клиенте. Разные окружения и задачи обращаются к различным объектам.

Что Делать и Где


Клиентская среда (браузер) является передним краем работы приложения. В этой среде, к примеру, Вы отображаете HTML-страницы в окне и обслуживаете истории сессий HTML-страниц, отображаемых в браузере в течение сессии. Объекты этой среды, следовательно, обязаны иметь возможность манипулировать страницами, окнами и историей.

По контрасту, в серверной среде Вы работаете с ресурсами сервера. Например, Вы можете установить соединение с реляционной базой данных, распределить информацию между пользователями приложения или манипулировать файловой системой сервера. Объекты этой среды обязаны иметь возможность манипулировать реляционной БД и файловой системой сервера.

Кроме того, HTML-страница не отображается на сервере. Она запрашивается на сервере для отображения на клиенте. Запрошенная страница может содержать клиентский JavaScript. Если запрошенная страница является частью приложения JavaScript, сервер может генерировать эту страницу "на лету".

При разработке приложения JavaScript помните о разнице между клиентской и серверной платформами. Различия показаны в следующей таблице.

Таблица 5.1 Сравнение Клиента и Сервера
Серверы Клиенты

Серверы обычно (хотя и не всегда) являются высокопроизводительными рабочими станциями с быстрыми процессорами и возможностью хранения больших объемов информации.

Клиенты часто (хотя и не всегда) являются настольными системами с маломощными процессорами и относительно небольшим объемом хранимых данных.

Серверы могут быть перегружены при одновременном доступе тысяч клиентов.

Клиенты часто - машины одного пользователя, поэтому можно передать часть нагрузки процессинга клиенту.

Предварительная обработка данных на клиенте также может уменьшить требования к пропускной способности сети, если клиентское приложение может компоновать данные.

Обычно имеются разные пути распределения приложения между сервером и клиентом. Некоторые задачи могут выполняться только на клиенте или только на сервере; другие могут выполняться на любом из них. Хотя нет какого-то определённого способа определить, что и где делать, Вы может следовать следующим общим правилам:

Основное правило - использовать клиентский процессинг (тэг SCRIPT) для следующих задач:

Использовать серверный процессинг (тэг SERVER) для следующих задач:

Служба JavaScript Session Management Service предоставляет объекты для сохранения информации, а клиентский JavaScript преходящ. Клиентские объекты существуют, пока пользователь имеет доступ к странице. Серверы могут объединять информацию от многих клиентов и многих приложений и могут сохранять большие объёмы данных в базе данных. Важно помнить обо всех этих характеристиках при распределении функциональности между клиентом и сервером.

Обзор Процессов Времени Прогона (Выполнения)


После того как Вы установили и стартовали приложение JavaScript, пользователь может получить к нему доступ.
Базовые процедуры таковы:

  1. Пользователь выполняет доступ к приложению по его URL в web-браузере, таком как Netscape Communicator. Браузер отправляет клиентский запрос страницы приложения на сервер.
  2. Если это запрос к странице с URL приложения, машина выполнения JavaScript, запущенная на сервере, находит информацию в web-файле, соответствующем этому URL. О деталях этого процесса и о том, что происходит на этом и на последующих двух этапах, см. в разделе "Процессинг Времени Прогона на Сервере".
  3. Машина времени выполнения конструирует HTML-страницу для отправки клиенту. Она выполняет байт-коды, ассоциированные с тэгами SERVER, из исходного кода HTML, создавая HTML-страницу на основе этих байт-кодов и иного HTML, имеющегося в оригинале. О том, как влиять на процесс конструирования страницы, см. в разделе "Конструирование HTML-Страницы".
  4. Машина выполнения высылает новую HTML-страницу (которая может содержать операторы клиентского JavaScript) клиенту.
  5. Машина выполнения JavaScript внутри web-браузера интерпретирует любые операторы клиентского JavaScript, форматирует вывод HTML и выводит результат пользователю.

Рисунок 5.1 иллюстрирует это процесс.

Рисунок 5.1   Процессинг запроса JavaScript-страницы

Конечно, пользователь обязан иметь Netscape Navigator (или иной браузер с возможностью выполнения JavaScript), чтобы клиент мог интерпретировать операторы клиентского JavaScript. Аналогично, если Вы создаёте страницу, содержащую серверный JavaScript, он должен быть установлен на Netscape-сервере, чтобы нормально функционировать.

Например, предположим, клиент запрашивает страницу с таким исходным кодом:

<html>
<head> <title> Add New Customer </title> </head>
<body text="#FFFF00" bgcolor="#C0C0C0" background="blue_marble.gif">
<img src="billlog2.gif">
<br>
<server>
if ( project.lock() ) {
   project.lastID = 1 + project.lastID;
   client.customerID = project.lastID;
   project.unlock();
}
</server>
<h1>Add a New Customer </h1>
<p>Note: <b>All</b> fields are required for the new customer
<form method="post" action="add.html"></p>
<p>ID:
<br> <server>write("<STRONG><FONT COLOR=\"#00FF00\">" +
   project.lastID + "</FONT></STRONG>");</server>
<!-- другие операторы html --> </body>
</html>

При доступе к этой странице машина выполнения выполняет на сервере код, ассоциированный с тэгами SERVER. (Этот код выделен жирным шрифтом.) Если ID нового потребителя 42, сервер высылает клиенту для отображения такую HTML-страницу:

<html>
<head> <title> Add New Customer </title> </head>
<body text="#FFFF00" bgcolor="#C0C0C0" background="blue_marble.gif">
<img src="billlog2.gif">
<br>
<h1>Add a New Customer </h1>
<p>Note: <b>All</b> fields are required for the new customer
<form method="post" action="add.html"></p>
<p>ID:
<br><STRONG><FONT COLOR="#00FF00">42</FONT></STRONG>
<!-- другие операторы html --> </body>
</html>

Серверный Язык. Обзор.


И клиентский, и серверный JavaScript реализуют язык JavaScript. Но каждый при этом добавляет специфические объекты и функции для работы в клиентской или серверной среде. Например, клиентский JavaScript включает объект form для представления формы на HTML-странице, а серверный JavaScript включает объект database для соединения с внешней реляционной БД.

В книге Клиентский JavaScript. Руководство. детально рассматривается ядро языка JavaScript и дополнительная специфика клиентского JavaScript.

ECMA, Европейская организация стандартизации систем информации и коммуникаций, выпустила стандарт ECMA-262 языка JavaScript. Вы можете загрузить эту спецификацию с сайта ECMA по адресу http://www.ecma.ch .

Прототипы


Как указано в книге Серверный JavaScript. Справочник. , Вы можете использовать свойство prototype многих классов, чтобы добавлять новые свойства в класс и во все его экземпляры. Как описано в разделе "Классы и Объекты", серверный JavaScript добавляет несколько классов и предопределённых объектов. В новых классах, имеющих свойство prototype, оно работает в серверном JavaScript точно так же, как и в клиентском JavaScript.

Вы можете использовать свойство prototype для добавления новых свойств в классы Blob, Connection, Cursor, DbPool, File, Lock, Resultset, SendMail и Stproc. Кроме того, Вы можете использовать свойство prototype класса DbBuiltin для добавления свойств в предопределённый объект database. Обратите внимание, что Вы не можете создать экземпляр класса DbBuiltin; вместо этого Вы используете объект database, предоставляемый машиной выполнения JavaScript.

Вы не можете использовать prototype с объектами client, project, request и server.

Так же, как и в клиентском JavaScript, Вы можете использовать свойство prototype для любого класса, который Вы определяете в своём приложении.

Помните, что все приложения JavaScript на сервере работают в одной среде. Вот почему Вы можете распределять информацию между клиентами и приложениями. Следствием этого, однако, является то, что при использовании свойства prototype для добавления нового свойства в любой серверный класс, добавленный языком JavaScript, новое свойство доступно всем приложениям, работающим на сервере, а не только приложению, в котором это свойство было добавлено. Это даёт возможность легко добавлять функциональность всем приложениям JavaScript на Вашем сервере.

В противоположность этому, если Вы добавляете свойство в класс, который Вы определили в своём приложении, это свойство доступно только в том приложении, где оно было создано.

Использование


Вам необходимо знать, как компилятор приложений JavaScript распознаёт клиентский и серверный JavaScript в HTML-файле.

Операторы клиентского JavaScript могут появляться в следующих ситуациях:

О деталях см. книгу Клиентский JavaScript. Руководство .

Операторы серверного JavaScript могут появляться в следующих ситуациях:

Заметьте, что Вы не можете специфицировать оператор серверного JavaScript как обработчик события. Дополнительно см. "Внедрение JavaScript в HTML".

Окружение (Рабочая Среда)


Возможности LiveConnect ядра языка JavaScript работают на сервере иначе, чем на клиенте. См. дополнительно Главу 14, "LiveConnect. Обзор.".

JavaScript предоставляет дополнительную функциональность без использования объектов. Вы получаете доступ к этой функциональности через функции, не ассоциированные с каким-либо объектом (глобальные функции). Ядро языка JavaScript имеет глобальные функции, описанные в следующей таблице (также как и другие функции, описанные в документации Ядра JavaScript).

Таблица 5.2  Глобальные Функции Ядра JavaScript
Функция Описание
escape

Возвращает 16-ричный код аргумента - символа из набора символов ISO Latin-1; используется при создании строк для добавления в URL.

unescape

Возвращает ASCII-строку для специфицированного значения; используется при разборе строки, добавленной в URL.

isNaN

Вычисляет аргумент для определения не является ли он "неЧислом".

parseFloat

Разбирает аргумент-строку и возвращает число с плавающей точкой.

parseInt

Разбирает аргумент-строку и возвращает целое число.

Серверный JavaScript добавляет глобальные функции, описанные в следующей таблице.

Таблица 5.3  Глобальные Функции Серверного JavaScript
Функция Описание
write

Добавляет операторы к генерируемой клиентской HTML-странице. (См. "Генерация HTML".)

flush

Очищает буфер вывода. (См. "Очистка Буфера Вывода".)

redirect

Перенаправляет клиента по специфицированному URL. (См. "Переход к Новому Клиентскому Запросу".)

getOptionValue

Получает значения отдельных опций в элементе HTML-формы SELECT. (См. "Использование Списков Выбора".)

getOptionValueCount

Получает количество опций в элементе HTML-формы SELECT. (См. "Использование Списков Выбора".)

debug

Выводит значения выражений в окне (фрэйме) трассировки. (См. "Использование Функции debug".)

addClient

Присоединяет клиентскую информацию к URL. (См. "Присоединение client-Свойств к URL Вручную".)

registerCFunction

Регистрирует внешнюю функцию для использования в серверном JavaScript. (См. "Регистрация Внешних Функций/Native Functions".)

callC

Вызывает внешнюю функцию. (См. "Использование Внешних Функций в JavaScript".)

deleteResponseHeader

Удаляет информацию из "шапки" ответа, высылаемого клиенту. (См. "Манипуляции с Запросом и Ответом".)

addResponseHeader

Добавляет новую информацию в "шапку" ответа, высылаемого клиенту. (См. "Манипуляции с Запросом и Ответом".)

ssjs_getClientID

Возвращает идентификатор для client -объекта, используемый при некоторых видах клиентской техники JavaScript. (См. "Уникальное Обращение к Объекту client".)

ssjs_generateClientID

Возвращает идентификатор, который Вы можете использовать для уникального специфицирования объекта client. (См. "Уникальное Обращение к Объекту client".)

ssjs_getCGIVariable

Возвращает значение специфицированной переменной окружения CGI. (См. "Доступ к Переменным CGI".)

Классы и Объекты


Для поддержания различных задач, выполняемых на каждой стороне, JavaScript имеет классы и предопределённые объекты, которые работают на клиенте, но не на сервере, и другие классы и предопределённые объекты, которые работают на сервере, но не на клиенте.

Важно!

Названия этих объектов зарезервированы для JavaScript. Не создавайте Ваши собственные объекты, используя эти имена.

Ядро языка JavaScript предоставляет классы, описанные в следующей таблице. Детальную информацию обо всех этих объектах см. в книге Серверный JavaScript. Справочник .

Таблица 5.4  Классы Ядра JavaScript
Класс Описание
Array

Массив.

Boolean

Булево значение.

Date

Дата.

Function

Специфицирует строку кода JavaScript, компилируемую как функция.

Math

Предоставляет основные математические константы и функции; например, свойство PI содержит значение pi.

Number

Примитивные числовые значения.

Object

Базовая функциональность всех объектов JavaScript.

Packages

Пакет Java в JavaScript. используется вместе с LiveConnect.

String

Строка JavaScript.

Серверный JavaScript включает классы ядра, но не классы клиентского JavaScript. Серверный JavaScript имеет свой набор дополнительных классов для поддержки необходимой функциональности, как показано в следующей таблице.

Таблица 5.5  Классы Серверного JavaScript
Класс Описание
Connection

Одиночное соединение с БД из пула соединений. (См. "Отдельные Соединения с БД").

Cursor

Курсор БД. (См. "Манипуляции с Результатами Выполнения Запроса с Помощью Курсоров").

DbPool

Пул соединений с базами данных. (См. "Пулы Соединений с Базами Данных").

Stproc

Хранимая процедура БД. (См. "Вызов Хранимых Процедур").

Resultset

Представляет информацию, возвращаемую хранимой процедурой БД. (См. "Вызов Хранимых Процедур".)

File

Предоставляет доступ к файловой системе сервера. (См. "Служба Файловой Системы".)

Lock

Предоставляет функциональность для безопасного совместного использования/sharing данных запросами, клиентами и приложениями. (См. "Безопасное Совместное Использование Объектов с Блокировкой".)

SendMail

Предоставляет функциональность для отправки электронной почты из вашего приложения JavaScript. (См. "Почтовая Служба".)

Кроме того, серверный JavaScript имеет предопределённые объекты, описанные в следующей таблице. Эти объекты доступны для каждого HTTP-запроса. Вы не можете создать дополнительные экземпляры какого-либо из этих объектов.

Таблица 5.6  Объекты Серверного JavaScript
Объект Описание
database

Соединение с базой данных. (См. "Соединение. Подходы.")

client

Инкапсулирует информацию о паре клиент/приложение, позволяя хранить эту информацию дольше, чем в течение одного HTTP-запроса. (См. "Объект client.")

project

Инкапсулирует информацию о приложении, которая хранится, пока приложение не прекратит работу на сервере. (См. "Объект project".)

request

Инкапсулирует информацию об отдельном HTTP-запросе. (См. "Объект request".)

server

Инкапсулирует глобальную информацию о сервере, которая хранится, пока сервер не остановится. (См. "Объект server".)

Внедрение JavaScript в HTML


Есть два способа встроить операторы серверного JavaScript в HTML-страницу:

Если Вы внедряете серверный JavaScript в HTML-страницу, машина выполнения JavaScript на сервере выполняет обнаруженные ею операторы при процессинге (обработке) страницы. Большинство операторов выполняют какие-либо операции на сервере, такие как открытие соединения с БД или блокировка совместно используемого объекта. Однако, если Вы используете функцию write в тэге SERVER или заключаете операторы в обратные кавычки, машина выполнения динамически генерирует новый HTML для модифицирования страницы, высылаемой клиенту.

Тэг SERVER


Тэг SERVER это наиболее распространённый способ внедрения серверного JavaScript в HTML-страницу. Вы можете использовать тэг SERVER в любой ситуации; обычно, однако, вместо него используются обратные кавычки, если Вы генерируете имена или значения атрибутов для HTML-страницы.

Большая часть операторов между тэгами <SERVER> и </SERVER> не появляется на HTML-странице, высылаемой клиенту. Эти операторы выполняются на сервере. Однако вывод вызовов функции write появляется в результирующем HTML.

Следующая выдержка из приложения Hello World иллюстрирует эти варианты:

<P>This time you are
<SERVER>
write(request.newname);
client.oldname = request.newname;
</SERVER>
<h3>Enter your name</h3>

Получив данный участок кода, машина выполнения генерирует HTML на базе значения request.newname в операторе write. Во втором операторе она просто выполняет операцию JavaScript, присваивая значение request.newname свойству client.oldname. Она не генерирует никакого HTML. Итак, если request.newname будет "Mr. Ed," машина выполнения генерирует из предыдущего отрывка следующий HTML:

<P>This time you are
Mr. Ed
<h3>Enter your name</h3>

Обратные Кавычки


Используйте обратные кавычки (`) для выделения выражений серверного JavaScript как заместителей для имён атрибутов или значений атрибутов HTML. JavaScript, внедрённый  в HTML с помощью обратных кавычек, автоматически генерирует HTML; Вам не нужно использовать write.

В целом тэги HTML имеют форму:

<TAG ATTRIB="value" [...ATTRIB="value"]>

где ATTRIB   это атрибут, а " value " это его значение. Значение в угловых скобках означает, что допускается любое количество пар атрибут/значение.

Если в обратные кавычки заключено выражение JavaScript, используемое как значение атрибута, машина выполнения JavaScript автоматически добавляет знак кавычки вокруг всего значения. Вы сами не вводите знаки кавычек, хотя Вам это может понадобиться для разграничения строковых литералов выражения, как в следующем примере. Машина выполнения не делает это для имён атрибутов, поскольку не предполагается заключение имён атрибутов в кавычки.

Например, рассмотри следующую строку из образца-приложения Hangman:

<IMG SRC=`"images\hang" + client.num_misses + ".gif"`>

Эта строка динамически генерирует имя изображения на основе значения client.num_misses. Обратные кавычки обрамляют выражение JavaScript, конкатенирующее строку "images\hang" и целочисленное значение client.num_misses и строку ".gif", давая строку типа "images\hang0.gif". Результатом будет HTML, такой как

<IMG SRC="images\hang0.gif">

Порядок ввода кавычек является критичным. Сначала идёт обратная кавычка, указывая, что следующее значение является выражением JavaScript, состоящим из строки ("images\hang"), соединяемой с целым числом (client.num_misses) и с другой строкой (".gif"). JavaScript конвертирует всё выражение до строки и добавляет необходимые знаки кавычек вокруг значения атрибута.

Вы должны внимательно использовать знаки двойных кавычек внутри обратных кавычек, поскольку содержащееся внутри них значение интерпретируется как литерал. Поэтому не окружайте выражения JavaScript, которые необходимо вычислить, знаками кавычек. Например, если значение свойства client.val будет NetHead, то данный оператор:

<A NAME=`client.val`>

генерирует такой HTML:

<A NAME="NetHead">

но следующий оператор:

<A NAME=`"client.val"`>

генерирует HTML:

<A NAME="client.val">

В качестве другого примера приведём два атрибута тэга ANCHOR - HREF и NAME. HREF делает тэг гиперссылкой, а NAME делает его именованным якорем. Следующие операторы используют переменную choice для установки свойств attrib и val объекта client и создают затем гиперссылку/hyperlink или цель/target, в зависимости от значений:

<SERVER>
if (choice == "link") {
   client.attrib = "HREF";
   client.val = "http://www.netscape.com";
}
if (choice == "target") {
   client.attrib = "NAME";
   client.val = "NetHead";
}
</SERVER>
<A `client.attrib`=`client.val`>Netscape Communications</A>

Если значением choice будет "link", результат будет:

<A HREF="http://home.netscape.com">Netscape Communications</A>

Если значением choice будет "target", результат будет:

<A NAME="NetHead">Netscape Communications</A>

Когда Использовать Эти Виды Техники


В большинстве случаев ясно, когда использовать тэг SERVER, а когда - обратные кавычки. Иногда, однако можно достичь того же результата другим путём ("Мы пойдём..."). В общем, лучше использовать обратные кавычки для внедрения значений JavaScript в тэги HTML, а в других случаях - тэг SERVER.

Например, в Hangman вместо

<IMG SRC=`"images\hang" + client.num_misses + ".gif"`>

можно записать

<SERVER>
write("<IMG SRC=\"images\hang");
write(client.num_misses);
write(".gif\">");
</SERVER>

Обратите внимание, что обратная наклонная черта (backslash) даёт возможность ввести знак кавычки внутри литеральной строки. Хотя результирующий HTML - тот же самый, в этом случае обратные кавычки предпочтительнее, поскольку исходник легче читать и редактировать.

Процессинг Времени Прогона на Сервере


В разделе "Обзор Процессинга Времени Выполнения" показано, что происходит на этапе прогона, если пользователь выполняет доступ к странице приложения JavaScript. В данном разделе детально рассматриваются этапы этого процесса со 2 по 4, чтобы Вы смогли лучше понять, что происходит на каждом этапе. Это описание предоставляет контекст для понимания того, что Вам нужно делать на клиенте и сервере.

При работе с приложениями JavaScript важно помнить об асинхронной природе процессов Web. Приложения JavaScript разрабатываются для использования многими пользователями одновременно. Машина выполнения JavaScript на сервере обрабатывает запросы нескольких пользователей по мере их поступления и выполняет их в порядке поступления.

В отличие от традиционного приложения, которое запускается отдельным пользователем на отдельной машине, Ваше приложение обязано поддерживать одновременный доступ нескольких пользователей. Фактически, поскольку каждый фрэйм (кадр) HTML-документа из нескольких фрэймов генерирует свой собственный запрос/request, для машины выполнения может оказаться, что запрос одного пользователя является множественным запросом.

HTTP (Hypertext Transfer Protocol) это протокол, по которому HTML-страница пересылается клиенту. Этот протокол является stateless\бесстатусным, то есть информация не сохраняется в период между запросами. В общем, любая информация, необходимая для обработки HTTP-запроса, должна пересылаться вместе с этим запросом. Это создаёт проблемы для многих приложений. Как использовать информацию одновременно различными пользователями приложения или даже различными запросами одного пользователя? Служба JavaScript Session Management Service была разработана для того, чтобы помочь разрешить эту проблему. Детально эта служба рассматривается в Главе 6, "Session Management Service." В данный момент просто помните, что машина выполнения автоматически обслуживает объекты client, server, project и request.

Если Netscape-сервер получает клиентский запрос на страницу приложения, он сначала выполняет авторизацию (идентификацию). Этот шаг является частью базовых функций администрирования сервера. Если попытка авторизации запроса не удалась, последующие шаги не выполняются. Если запрос получил авторизацию сервера, машина выполнения JavaScript продолжает работу. Она выполняет следующие шаги, описанные в последующих разделах:

  1. Конструирует новый объект request и конструирует или восстанавливает объект client.
  2. Находит страницу для запроса и начинает создание HTML-страницы для отправки клиенту.
  3. Для каждого участка исходной HTML-страницы: добавляет его в буфер или исполняет код.
  4. Сохраняет свойства объекта client.
  5. Высылает HTML клиенту.
  6. Уничтожает объект request и сохраняет или уничтожает объект client.

Шаг 1. Создание объекта request и конструирование или восстановление объекта client


Инициализируются встроенные свойства объекта request, такие как IP-адрес и элементы формы, ассоциированные с данным request. Если URL запроса специфицирует другие свойства, они инициализируются для объекта request, как описано в разделе "Кодирование Информации в URL".

Если объект client уже существует, машина выполнения запрашивает его на основе специфицированной техники обслуживания клиента. (См. "Техника Обслуживания Объекта client"). Если объект client не существует, машина выполнения конструирует новый объект без свойств.

Вы не можете предвидеть, в каком порядке эти объекты конструируются.

Шаг 2. Поиск исходной страницы и начало конструирования HTML-страницы


Когда Вы компилировали исходный код JavaScript, исходник включал HTML-страницы с операторами серверного JavaScript. Главной задачей машины выполнения является конструирование из одной из этих исходных страниц HTML-страницы, содержащей только HTML и операторы клиентского JavaScript. При создании этой HTML-страницы машина выполнения сохраняет её части в области памяти, называемой буфером, пока не придёт время отправки буферизованного содержимого клиенту.

Шаг 3. Добавить в буфер вывода или выполнить код


Этот шаг выполняется для каждого участка кода исходной страницы. Детали процесса выполнения различных серверных операторов рассматриваются далее в этом учебнике. Дополнительно см. "Конструирование HTML-Страницы".

Для данного запроса/request машина выполнения выполняет этот шаг, пока не произойдёт одно из следующих событий:

Шаг 4. Сохранение свойств объекта client


Машина выполнения сохраняет свойства объекта client непосредственно перед первой отправкой части HTML-страницы клиенту. Она сохраняет эти свойства только один раз. Машина выполнения может повторять шаги 3 и 5, но не может повторить данный шаг.

Машина выполнения сохраняет свойства в этот момент, чтобы поддерживать один из видов техники обслуживания объекта client. Например, схема кодирования клиентского URL высылает свойства client'а в шапке/header HTML-файла. Поскольку шапка высылается как первая часть файла, свойства client'а обязаны быть затем высланы.

Следовательно, Вы должны учитывать, где в Вашем файле-источнике устанавливаются свойства client'а. Вы всегда должны изменять свойства client'а в файле до любого вызова redirect или flush и до генерирования 64KB HTML-вывода.

Если Вы изменяете значения свойств объекта client в коде после того как HTML был выслан клиенту, эти изменения будут действовать для оставшейся части клиентского запроса, но затем будут отменены. Отсюда: следующий клиентский запрос не получит эти значения свойств; он получит значения, действовавшие в тот момент, когда содержимое было в первый раз отправлено клиенту. Например, ваш код содержит такие операторы:

<HTML>
<P>The current customer is
<SERVER>
client.customerName = "Mr. Ed";
write(client.customerName);
client.customerName = "Mr. Bill";
</SERVER>
<P>The current customer really is
<SERVER>
write(client.customerName);
</SERVER>
</HTML>

Эта серия операторов даст в результате такой HTML, отправляемый клиенту:

<P>The current customer is Mr. Ed
<P>The current customer really is Mr. Bill

Теперь, когда появится следующий клиентский запрос, значение свойства client.customerName будет "Mr. Bill". Этот очень похожий набор операторов даст в результате тот же HTML:

<HTML>
<P>The current customer is
<SERVER>
client.customerName = "Mr. Ed";
write(client.customerName);
flush();
client.customerName = "Mr. Bill";
</SERVER>
<P>The current customer really is
<SERVER>
write(client.customerName);
</SERVER>
</HTML>

Однако при появлении следующего клиентского запроса значение client.customerName будет "Mr. Ed"; а не "Mr. Bill".

Дополнительно см. "Техника Обслуживания Объекта client".

Шаг 5. Отправка HTML клиенту


Сервер отсылает содержимое страницы клиенту. Для страниц без операторов серверного JavaScript сервер просто передаёт HTML клиенту. Для других страниц - машина выполнения реализует логику приложения для конструирования HTML и затем высылает сгенерированную страницу клиенту.

Шаг 6. Уничтожение объекта request и сохранение или уничтожение объекта client


Машина выполнения разрушает объект request, сконструированный для данного клиентского запроса. Она сохраняет значения объекта client и разрушает физический объект JavaScript. Она не разрушает объекты project или server.

Конструирование HTML-Страницы


Когда Вы компилируете приложение JavaScript, исходники состоят из HTML-страниц, содержащих операторы серверного JavaScript, и, возможно, HTML-страницы, не содержащие операторов серверного JavaScript. Если пользователь получает доступ к странице, которая не содержит серверных операторов, сервер высылает страницу обратно, как и любую другую HTML-страницу. Если пользователь получает доступ к странице, которая содержит серверные операторы, машина выполнения на сервере конструирует HTML-страницу для отправки в ответе, используя одну из исходных страниц Вашего приложения.

Машина выполнения сканирует исходную страницу. При обнаружении операторов HTML клиентского JavaScript она присоединяет их к создаваемой странице. При обнаружении операторов серверного JavaScript она выполняет их. Хотя большинство операторов серверного JavaScript выполняются на сервере, некоторые влияют на конструируемую страницу. В следующих разделах рассматриваются три функции: write, flush и redirect, которые влияют на обрабатываемую HTML-страницу.

Генерирование HTML


Как уже было сказано ранее в этой главе, функция write генерирует HTML на основе значения выражения JavaScript, заданного в качестве аргумента. Например, рассмотрим оператор:

write("<P>Customer Name is:" + project.custname + ".");

В ответ на этот оператор JavaScript генерирует HTML, вставляя тэг параграфа и некоторый текст, соединённый со значением свойства custname объекта project. Например, если свойство будет иметь значение "Fred's software company", клиент получит следующий HTML:

<P>Customer Name is: Fred's software company.

Как кажется клиенту, это нормальный HTML. Однако он в действительности динамически сгенерирован машиной выполнения JavaScript.

Очистка Буфера Вывода


Для повышения производительности, JavaScript буферизует конструируемую им HTML-страницу. Функция flush сразу высылает данные из внутреннего буфера клиенту. Если Вы явно не вызываете функцию flush, JavaScript высылает данные клиенту после создания каждых 64KB содержимого конструируемой HTML-страницы.

Не путайте функцию flush с методом flush класса File. (Об использовании класса File для ввода и вывода в файл см. "Служба Файловой Системы").

Вы можете использовать flush для управления временем переноса данных клиенту. Например, Вы можете очищать буфер до операции, создающей задержку/delay, такой как запрос к базе данных. Также, если запрос к БД запрашивает большое количество рядов, очистка буфера каждый раз после получения нескольких рядов предотвращает паузы при отображении данных.

ПРИМЕЧАНИЕ: Если Вы используете клиентские куки для обслуживания свойств объекта client, Вы обязаны делать все изменения объекта client до очистки буфера. Дополнительно см. "Техника Обслуживания Объекта client".

Следующий фрагмент кода показывает, как используется flush. Предположим, Ваше приложение должно выполнить некоторые действия с каждым потребителем/customer в Вашей БД потребителей. Если потребителей много, процесс может затянуться. Поэтому, для того чтобы пользователь не ждал у застывшего экрана, Ваше приложение может высылать вывод клиенту до начала обработки и затем вновь - после конца обработки каждого ряда. Для этого Вы должны использовать примерно такой код:

flush();
conn.beginTransaction();
cursor = conn.cursor ("SELECT * FROM CUSTOMER", true);
while ( cursor.next() ) {
   // ... обработка ряда ...
   flush();
}
conn.commitTransaction();
cursor.close();

Переход к Новому Клиентскому Запросу


Функция redirect прерывает текущий клиентский запрос и стартует новый по специфицированному URL. Например, у вас имеется оператор:

redirect("http://www.royalairways.com/apps/page2.html");

Когда машина выполняет это оператор, она прерывает текущий запрос. Машина выполнения не продолжает обработку страницы-оригинала. Следовательно любые операторы HTML или JavaScript, идущие в оригинальной странице после вызова redirect, будут утеряны. Клиент сразу загрузит указанную страницу, отбросив предыдущее содержимое.

Параметром для redirect может быть любой оператор серверного JavaScript, вычисляемый до URL. Таким образом, Вы можете динамически генерировать URL, используемый в redirect. Например, если страница определяет переменную choice, Вы можете перенаправить клиента на страницу в зависимости от значения choice таким образом:

redirect ("http://www.royalairways.com/apps/page"
   + choice + ".html");

Если Вам нужно удостовериться, что текущие свойства client'а доступны в новом запросе и что Вы используете один из видов техники обслуживания объекта client на основе URL, Вы должны кодировать свойства в URL, передаваемом Вами в redirect. О том, как это сделать, см. "Присоединение Свойств client'а к URL Вручную".

В целом свойства объекта request и переменные верхнего уровня JavaScript существуют только в течение одиночного клиентского запроса. Если Вы выполняете перенаправление на новую страницу, Вам может понадобиться сохранить некоторую информацию для нескольких запросов. Вы можете сделать это, присоединив имена и значения свойств к URL, как описано в разделе "Кодирование Информации в URL".

Доступ к Переменным CGI


Как и большинство других web-серверов, серверы Netscape устанавливают значения для определённого набора переменных окружения, называемых CGI-переменными, при установке контекста для запуска CGI-скрипта. Предполагается, что создатели CGI-скриптов могут использовать эти переменные в своих скриптах.

По контрасту, Netscape web-серверы не устанавливают отдельного окружения для приложений серверного JavaScript. Тем не менее, некоторая часть информации, обычно устанавливаемой в CGI-переменных, может использоваться в приложениях JavaScript. Машина выполнения предоставляет несколько механизмов для доступа к этой информации:

В следующей таблице перечислены свойства объекта request, соответствующие CGI-переменным. Дополнительно об этих свойствах и об объекте request в целом см. "Объект request".

Таблица 5.7  CGI-переменные, доступные как свойства объекта request
CGI-переменная Свойство Описание
AUTH_TYPE auth_type

Тип авторизации, если запрос защищён авторизацией любого типа. Netscape web-серверы поддерживают базовую авторизацию доступа HTTP.
Пример значения: basic

REMOTE_USER auth_user

Имя локального HTTP-пользователь web-браузера, если авторизации доступа HTTP была активирована для данного URL. Заметьте, что это не способ определения имени пользователя, получившего доступ к Вашей программе. Пример значения: ksmith

REQUEST_METHOD method

HTTP-метод, ассоциированный с запросом. Приложение может использовать его для определения соответствующего ответа на запрос.
Пример значения: GET

SERVER_PROTOCOL protocol

Уровень протокола HTTP, поддерживаемый клиентским программным обеспечением. Пример значения: HTTP/1.0

QUERY_STRING query

Информация запрашивающей HTML-страницы; если имеется "?", информация в URL, идущая после знака "?". Пример значения: x=42

Серверная функция ssjs_getCGIVariable даёт Вам доступ к переменным окружения, установленным в серверном процессе, включая CGI-переменные, перечисленные в следующей таблице.

Таблица 5.8  CGI-переменные, доступные через ssjs_getCGIVariable
Переменная Описание
AUTH_TYPE

Тип авторизации, если запрос защищён авторизацией любого типа. Netscape web-серверы поддерживают базовую авторизацию доступа HTTP.
Пример значения: basic

HTTPS

Если на сервере активна служба безопасности/security, значение этой переменной ON; иначе - OFF. Пример значения: ON

HTTPS_KEYSIZE

Количество битов в ключе сессии, используемом для шифрования сессии, если безопасность on. Пример значения: 128

HTTPS_SECRETKEYSIZE

Количество битов, используемых для генерации private-ключа сервера.
Пример значения: 128

PATH_INFO

Информация пути, установленная браузером. Пример: /cgivars/cgivars.html

PATH_TRANSLATED

Фактическое системное pathname/имя пути , содержащегося в PATH_INFO. Пример: /usr/ns-home/myhttpd/js/samples/cgivars/cgivars.html

QUERY_STRING

Информация запрашивающей HTML-страницы; если имеется "?", информация в URL, идущая после знака "?". Пример значения: x=42

REMOTE_ADDR

IP-адрес хоста, отправившего запрос. Пример: 198.93.95.47

REMOTE_HOST

Если DNS на сервере включена, имя хоста, отправившего запрос; иначе - его IP-адрес. Пример: www.netscape.com

REMOTE_USER

Имя локального HTTP-пользователя web-браузера, если авторизация доступа HTTP была активирована данным URL. Заметьте, что это не способ определения user name того, кто выполнил доступ к Вашей программе. Пример: ksmith

REQUEST_METHOD

HTTP-метод, ассоциированный с запросом. Приложение может использовать его для определения ответа на запрос. Пример: GET

SCRIPT_NAME

pathname к данной странице, как он введён в URL. Пример: cgivars.html

SERVER_NAME

hostname или IP-адрес, по которому приложение JavaScript запущено, как они даны в URL. Пример: piccolo.mcom.com

SERVER_PORT

TCP-порт, по которому запущен сервер. Пример: 2020

SERVER_PROTOCOL

Уровень протокола HTTP, поддерживаемый клиентским программным обеспечением. Пример: HTTP/1.0

SERVER_URL

URL, введённый пользователем для доступа к данному серверу. Пример: https://piccolo:2020

Здесь приведён синтаксис ssjs_getCGIVariable:

value = ssjs_getCGIVariable("name");

Этот оператор устанавливает в переменную value значение CGI-переменной name. Если предоставленный вами аргумент не является одной из CGI-переменных, перечисленных в Таблице 5.8, машина выполнения ищет переменную окружения с этим именем в среде сервера. Если она найдена, машина выполнения возвращает значение; иначе, возвращает null. Например, следующий код присваивает значение стандартной переменной окружения CLASSPATH переменной JavaScript classpath:

classpath = ssjs_getCGIVariable("CLASSPATH");

Метод httpHeader объекта request возвращает шапку/header текущего клиентского запроса. Для CGI-скрипта Netscape web-серверы устанавливают CGI-переменные для некоторой информации в шапке. Для приложений JavaScript Вы получаете эту информацию непосредственно из шапки. Таблица 5.9 показывает информацию, доступную как переменные CGI в среде CGI, но как свойства шапки - в серверном JavaScript. В свойствах шапки символы подчёркивания в имени CGI-переменной (_) заменяются на тире (-); например, CGI-переменная CONTENT_LENGTH соответствует свойству шапки content-length.

Таблица 5.9 CGI-переменные, доступные через клиентские "шапки"
CGI-переменная Описание
CONTENT_LENGTH

Количество байтов, отправленных клиентом.

CONTENT_TYPE

Тип данных, отправленных клиентом, если форма отправлена методом POST.

HTTP_ACCEPT

Перечисляет типы данных, которые может принимать клиент.

HTTP_USER_AGENT

Идентифицирует браузер, используемый для доступа к Вашей программе.

HTTP_IF_MODIFIED_SINCE

Дата, установленная в соответствии со стандартным временем GMT (по Гринвичу), дающая возможность отправлять клиенту ответ на запрос только тогда, когда дата была изменена после данной даты.

Дополнительно о манипулировании клиентской "шапкой" см. "Манипуляции с Запросом и Ответом".

В таблице даны CGI-переменные, не поддерживаемые серверным JavaScript, которые не могут быть применены при запуске приложений JavaScript.

Таблица 5.10  CGI-переменные, не поддерживаемые серверным JavaScript
Переменная Описание
GATEWAY_INTERFACE

Версия CGI, запущенная на сервере. Не применяется к приложениям JavaScript.

SERVER_SOFTWARE

Тип запущенного сервера. Недоступна для приложений JavaScript.

Сообщение Между Сервером и Клиентом


Нередко Вашим приложениям JavaScript нужно передать информацию либо с сервера клиенту, либо с клиента на сервер. Например, когда пользователь в первый раз выполняет доступ к приложению videoapp, оно динамически генерирует список категорий видео-файлов из текущего содержимого БД. Эта информация, генерируемая на сервере, должна быть передана обратно клиенту. И наоборот, когда пользователь щёлкает на категории из этого списка, выбор пользователя должен быть передан обратно на сервер, чтобы он мог сгенерировать набор файлов.

Отправка Значений с Клиента на Сервер


Есть несколько способов отправки информации с клиента на сервер:

Доступ к Значениям Формы


Формы это альфа и омега приложений на JavaScript. Вы используете такие элементы формы как текстовые поля и радио-кнопки в качестве первичного механизма переноса данных с клиента на сервер. Когда пользователь щёлкает на кнопке Submit, браузер отправляет значения, введённые форму, на сервер для обработки.

Атрибут ACTION тэга FORM определяет приложение, которому отправляются значения. Для того чтобы отправить информацию приложению на сервер, используйте URL приложения как значение атрибута ACTION.

Если документ, содержащий форму, является скомпилированной частью того же самого приложения, Вы можете просто предоставить имя страницы вместо полного URL. Например, вот тэг FORM из приложения-примера Hangman:

<FORM METHOD="post" ACTION="hangman.html">

Формы, отправляемые приложениям на серверном JavaScript, могут использовать get или post в качестве значения атрибута METHOD.

ПРИМЕЧАНИЕ: Приложения на серверном JavaScript не поддерживают автоматическую выгрузку файлов. То есть, если специфицированная action это страница в приложении JavaScript, Вы отправляете элемент INPUT с типом TYPE="file", Ваше приложение обязано само обработать этот файл, как описано в разделе "Манипуляции с Запросом и Ответом".

Каждый элемент ввода HTML-формы соответствует свойству объекта request. Имя свойства специфицируется атрибутом NAME элемента формы. Например, следующий HTML создаёт свойство объекта request под названием guess, которое принимает одиночный символ в текстовом поле. Вы обращаетесь к этому свойству в серверном JavaScript как к request.guess.

<FORM METHOD="post" ACTION="hangman.html">
<P>
What is your guess?
<INPUT TYPE="text" NAME="guess" SIZE="1">

Элемент SELECT, дающий возможность множественного выбора, требует особого обращения, поскольку это единственное свойство, которое может иметь несколько значений. Вы можете использовать функцию getOptionValue для получения значений выбранных опций в списке множественного выбора. Дополнительно см. "Использование Списков Select".

Информацию об объекте request см. в разделе "Объект request".

Если Вы хотите обработать данные сначала на стороне клиента, Вы должны создать функцию клиентского JavaScript для выполнения обработки значений элементов формы и передать затем вывод клиентской функции элементу формы. Вы можете скрыть/hide этот элемент, чтобы он не отображался пользователю, если Вы хотите выполнить клиентский препроцессинг.

Например, у Вас имеется функция клиентского JavaScript под названием calc, выполняющая расчёт на основе пользовательского ввода. Вы хотите передать результат работы этой функции Вашему приложению для дальнейшей обработки. Сначала Вам нужно определить скрытый элемент формы для результата:

<INPUT TYPE="hidden" NAME="result" SIZE=5>

Затем Вам нужно создать обработчик события onClick для кнопки Submit, который назначает вывод функции в скрытый элемент:

<INPUT TYPE="submit" VALUE="Submit"
   onClick="this.form.result.value=calc(this.form)">

Значение элемента result отправляется вместе с другими значениями элементов формы. Обратиться к этому значению в приложении можно request.result.

Использование Списков Select


HTML-тэг SELECT, используемый с атрибутом MULTIPLE, даёт возможность ассоциировать несколько значений с одним элементом формы. Если Вашему приложению нужны списки с возможностью выбора нескольких опций, Вы используете функцию getOptionValue для получения значений в JavaScript. Синтаксис getOptionValue таков:

itemValue = getOptionValue(name, index)

Здесь name это строка, специфицированная как атрибут NAME тэга SELECT, а index это порядковый индекс выбранной опции, начиная с 0. Функция getOptionValue возвращает значение выбранного элемента, как специфицировано ассоциированным тэгом OPTION.

Функция getOptionValueCount возвращает количество опций (специфицированных тэгами OPTION) в списке выбора. Она требует только одного аргумента, строки, содержащей имя тэга SELECT.

Например, у Вас имеется следующий элемент:

<SELECT NAME="what-to-wear" MULTIPLE SIZE=8>
   <OPTION SELECTED>Jeans
   <OPTION>Wool Sweater
   <OPTION SELECTED>Sweatshirt
   <OPTION SELECTED>Socks
   <OPTION>Leather Jacket
   <OPTION>Boots
   <OPTION>Running Shoes
   <OPTION>Cape
</SELECT>

Вы можете обработать ввод из этого select-списка таким образом:

<SERVER>
var i = 0;
var howmany = getOptionValueCount("what-to-wear");
while ( i < howmany ) {
   var optionValue =
      getOptionValue("what-to-wear", i);
   write ("<br>Item #" + i + ": " + optionValue + "\n");
   i++;
}
</SERVER>

Если пользователь оставил выбор по умолчанию, скрипт возвратит:

Item #0: Jeans
Item #1: Sweatshirt
Item #2: Socks

Кодирование Информации в URL


Вы можете вручную кодировать свойства объекта request в URL, по которому выполняется доступ к странице Вашего приложения. При создании URL используется следующий синтаксис:

URL?varName1=value1[&varName2=value2...]

Здесь URL это базовый URL, каждое varName N   это имя свойства, каждое value N   это соответствующее свойству значение (с мнемониками специальных символов). В этой схеме после базового URL идёт знак вопроса (?), после которого, в свою очередь, идут пары имён свойств и их значений. Каждая пара отделяется амперсандом (&). Когда машина выполнения на сервере получает результирующий URL в качестве клиентского запроса, она создаёт свойство объекта request под названием varName N   для каждой переменной.

Например, следующий HTML определяет гиперссылку на страницу, инстанциирующую свойства объекта request i и j в 1 и 2, соответственно. Операторы JavaScript в refpage.html могут затем обратиться к эти переменным request.i и request.j.

<A HREF="refpage.html?i=1&j=2">Click Here</A>

Вместо использования статической URL-строки, как в предыдущем примере, Вы можете использовать операторы серверного или клиентского JavaScript для динамической генерации URL, кодирующего значения свойств. Например, Ваше приложение может включать страницу:

<HTML>
<HEAD>
<SCRIPT>
function compute () {
   // ... заменить подходящими расчётами,    // которые возвращают строку поиска ...
   return "?num=25";
}
</SCRIPT>
</HEAD>
<BODY>
<a HREF="refpage.html" onClick="this.search=compute()">
Click here to submit a value.</a></p>
</BODY>
</HTML>

В данном случае, если пользователь щёлкнет на ссылке, машина выполнения на клиенте запустит на выполнение обработчик события onClick. Этот обработчик устанавливает часть поиска из URL в ссылке в какую-нибудь строку, возвращённую функцией compute. Когда машина выполнения на сервере получит этот запрос, она создаст свойство num объекта request и установит его значение в 25.

В качестве второго примера Вы можете добавить свойства объекта request в URL, созданный в серверном скрипте. Это особенно применимо, если Вы перенаправляете клиентский запрос на новую страницу. Чтобы добавить свойства объекта request в серверный скрипт, Вы можете использовать такой оператор:

<A HREF=`"refpage.html?i=" + escape(i) + "&j=" + escape(j)`>
   Click Here</A>

Если вы создаёте URL в операторе серверного JavaScript, свойства объекта client не добавляются автоматически. Если Вы используете технику на основе URL для объекта client, используйте функцию addClient для генерирования окончательного URL. В этом примере оператор может быть таким:

<A HREF=`addClient("refpage.html?i=" + escape(i)
   + "&j=" + escape(j))`>Click Here</A>

Об использовании addClient см. "Присоединение Свойств Объекта client к URL Вручную".

Функция escape ядра JavaScript даёт возможность кодировать имена или значения, присоединённые к URL, включая специальные символы. Вообще, если приложению необходимо генерировать имена и значения собственных свойств в URL запроса, Вы должны использовать escape, чтобы гарантировать корректную интерпретацию всех значений. Дополнительно см. книгу Серверный JavaScript. Справочник .

Помните, что URL не изменяется, если пользователь перезагружает его, хотя содержимое страницы может измениться. Любые свойства, высланные в оригинальном URL, восстанавливают свои значения в URL, имевшиеся на момент его первой отправки, независимо от любых возможных изменений, сделанных при обработке. Например, если пользователь щёлкнул кнопку Reload для перезагрузки URL в предыдущем примере, i и j снова установятся в 1 и 2, соответственно.

Отправка Значений с Сервера Клиенту


Приложение JavaScript сообщается с клиентом через HTML и клиентский JavaScript. Если Вам нужно просто вывести информацию пользователю, нет никаких проблем: Вы создаёте HTML для форматирования этой информации так, как она будет отображаться.

Однако Вам может понадобиться выслать значения непосредственно клиентскому скрипту. Можно сделать это по-разному, включая такие способы:

Значения по Умолчанию Формы и Скрытых Элементов Формы


Чтобы отобразить HTML-форму с набором значений по умолчанию в элементах формы, используйте тэг INPUT для создания необходимых элементов формы, замещая выражения серверного JavaScript атрибутов VALUE. Например, Вы можете использовать следующий оператор для отображения элемента text и установки значения по умолчанию на основе значения переменной client.custname:

<INPUT TYPE="text" NAME="customerName" SIZE="30"
   VALUE=`client.custname`>

Начальным значением этого текстового поля становится значение переменной client.custname. Так, если значением client.custname является Victoria, клиенту будет выслан такой оператор:

<INPUT TYPE="text" NAME="customerName" SIZE="30" VALUE="Victoria">

Вы может использовать аналогичную технику со скрытыми элементами формы, если не хотите показывать значения пользователю, как в следующем примере:

<INPUT TYPE="hidden" NAME="custID" SIZE=5 VALUE=`client.custID`>

В обоих случаях Вы можете использовать эти значения клиентского JavaScript в значениях свойств объектов, доступных клиенту. Если эти два элемента находятся в форме с именем entryForm, то значения станут свойствами JavaScript document.entryForm.customerName и document.entryForm.custID, соответственно. Вы можете затем выполнять обработку этих значений на стороне клиента. См. также книгу Клиентский JavaScript. Руководство .

Прямая Замена


Вы можете также использовать серверный JavaScript для генерирования клиентских скриптов. Эти значения могут использоваться в последовательности операторов на клиенте. В качестве простого примера Вы можете инициализировать клиентскую переменную по имени budget на основе значения client.amount таким образом:

<p>The budget is:
<SCRIPT>
<SERVER>
write("var budget = " + client.amount);
</SERVER>
document.write(budget);
</SCRIPT>

Если значение client.amount равно 50, это сгенерирует такой JavaScript:

<p>The budget is:
<SCRIPT>
var budget = 50
document.write(budget);
</SCRIPT>

При запуске на клиенте это будет выглядеть так:

The budget is: 50

Использование Кук


Куки это механизм, который Вы можете использовать на клиенте для сохранения информации между запросами. эта информация находится в файле с названием cookie.txt (куки-файл), хранящемся на клиентской машине. Протокол Netscape cookie детально описан в книге Клиентский JavaScript. Руководство .

Вы можете использовать куки для отправки информации в обоих направлениях, от клиента серверу и с сервера клиенту. Куки, высылаемые с клиента, становятся свойствами объекта client или объекта request. Хотя Вы можете выслать с сервера клиенту любое строковое значение в качестве куки, простейший метод будет - отправить свойства объекта client.

Свойства Объекта client как Куки


Если приложение использует технику клиентских кук для работы с объектом client, машина выполнения на сервере сохраняет имена и значения свойств объекта client как куки на клиенте. Об использовании кук для работы с объектом client см. раздел "Техника Работы с Объектом client".

Для свойства объекта client propName   машина выполнения автоматически создаёт куку с именем NETSCAPE_LIVEWIRE. propName , принимая, что приложение использует технику работы с клиентскими куками. Машина выполнения кодирует значения свойств так, как это требуется по протоколу кук Netscape cookie protocol.

Для доступа к этим кукам в клиентском JavaScript Вы можете извлечь эту информацию путём использования свойства document.cookie и такой функции как getSSCookie, как показано здесь:

function getSSCookie(name) {
   var search = "NETSCAPE_LIVEWIRE." + name + "=";
   var retstr = "";
   var offset = 0;
   var end = 0;
   if (document.cookie.length > 0) {
      offset = document.cookie.indexOf(search);
      if (offset != -1) {
         offset += search.length;
         end = document.cookie.indexOf(";", offset);
         if (end == -1)
            end = document.cookie.length;
         retstr = unescape(document.cookie.substring(offset, end));
      }
   }
   return(retstr)
}

Функция getSSCookie не является предопределённой функцией JavaScript. Если Вам нужна похожая функциональность, Вы обязаны определить её (функцию) в Вашем приложении.

Чтобы отправленная на сервер информация стала свойством объекта client, добавьте куку с именем, имеющим форму NETSCAPE_LIVEWIRE. propName. Предположим, Ваше приложение использует технику работы с клиентскими куками, а машина выполнения на сервере создаёт свойство объекта client под названием propName   для данной куки.

Тогда Вы можете использовать функцию типа следующей:

function setSSCookie (name, value, expire) {
   document.cookie =
      "NETSCAPE_LIVEWIRE." + name + "="
      + escape(value)
      + ((expire == null) ? "" : ("; expires=" + expire.toGMTString()));
}

Здесь функция setSSCookie также не является предопределённой функцией JavaScript. Если Вам необходима аналогичная функциональность, Вы обязаны определить функцию в Вашем приложении.

Вы можете вызывать эти функции в клиентском JavaScript для получения набора значений свойств объекта client, как в следующем примере:

var value = getSSCookie ("answer");
if (value == "") {
   var expires = new Date();
   expires.setDate(expires.getDate() + 7);
   setSSCookie ("answer", "42", Expires);
}
else
   document.write ("The answer is ", value);

Эта группа операторов проверяет, имеется ли свойство объекта client с названием answer. Если нет, код создаёт его и устанавливает значение 42; если найдено, выводится его значение.

Другие Куки


Когда серверу высылается запрос на страницу приложения JavaScript, шапка/header запроса включает все куки, установленные в данный момент для приложения. Можно использовать метод request.httpHeader для доступа к этим кукам из серверного JavaScript и присвоения их значений серверным переменным. И наоборот, Вы можете использовать функцию addResponseHeader для добавления новых кук в ответ, высылаемый обратно клиенту. Эта функциональность  описана в разделе "Манипуляция с Запросом и Ответом".

На клиентской стороне Вы можете использовать функцию вроде приведённой здесь для доступа к куке:

function GetCookie (name) {
   var arg = name + "=";
   var alen = arg.length;
   var clen = document.cookie.length;
   var i = 0;
   while (i < clen) {
      var j = i + alen;
      if (document.cookie.substring(i, j) == arg) {
         var end = document.cookie.indexOf (";", j);
         if (end == -1)
            end = document.cookie.length;
         return unescape(document.cookie.substring(j, end));
      }
      i = document.cookie.indexOf(" ", i) + 1;
      if (i == 0) break;
   }
   return null;
}

И Вы может использовать функцию типа приведённой ниже для установки куки на клиенте:

function setCookie (name, value, expires, path, domain, secure) {
   document.cookie =
      name + "="
      + escape(value)
      + ((expires) ? "; expires=" + expires.toGMTString() : "")
      + ((path) ? "; path=" + path : "")
      + ((domain) ? "; domain=" + domain : "")
      + ((secure) ? "; secure" : "");
}

Если путь, специфицированный Вами для куки, находится в Вашем приложении JavaScript, то эта кука будет отправлена в ответ на любой запрос к приложению.

Вы можете использовать эту технику для передачи информации куки между клиентом и сервером, независимо от вида используемой техники работы с объектом client.

Сбор Мусора


Серверный JavaScript имеет сборщика мусора, который автоматически освобождает память, выделенную для объекта, более не используемого. В большинстве случаев нет необходимости понимать досконально работу сборщика мусора. Этот раздел даёт обзор  сборщика мусора и информацию о том, когда он вызывается.

Важно!

Этот раздел даёт возможность продвинутым пользователям взглянуть на внутренние процессы JavaScript. Netscape не гарантирует, что эти алгоритмы останутся такими же в последующих релизах.

Пространство объекта в JavaScript состоит из арен. То есть машина выполнения JavaScript размещает набор арен, из которого затем размещает объекты. Если машина выполнения получает запрос на новый объект, она сначала просматривает список свободных арен. Если в списке свободных есть место, машина выделяет его. Иначе машина выполнения выделяет место в текущей используемой арене. Если используются все арены, машина размещает новую арену. Если все объекты арены - мусор, сборщик мусора освобождает арену.

Строка JavaScript обычно размещается как GC-объект. Строка имеет ссылку на байты строки, которая также размещается в куче/heap процесса. Если строковой объект подвергся сборке мусора, байты строки высвобождаются.

Работа сборщика мусора JavaScript основана на пометке и уничтожении. Сборщик не перемещает объекты. Он всегда обрабатывает корневой набор объектов. Этот корневой набор/root set включает в себя стэк JavaScript, объект global для контекста JavaScript и любые объекты JavaScript, которые были явно добавлены в корневой набор. В фазе разметки сборщик мусора помечает все объекты, достижимые из корневого набора. В конечной фазе все непомеченные объекты уничтожаются. Все убранные объекты собираются в список свободных.

Сборка мусора считается необходимой, если количество текущих используемых байтов в 1.5 раза превышает количество байтов, бывших в использовании в конце последней уборки мусора. Машина выполнения проверяет это условие в следующих точках и начинает уборку, если это необходимо:

Обработка Ошибок в Серверном JavaScript


Функция  ssjs_onError, если она определена в Вашем приложении, вызывается в случае ошибки серверного JavaScript, такой как "undefined variable name/имя переменной не определено". В функции ssjs_onError Вы можете делать всё, что можно делать в функции серверного JavaScript, включая доступ к объектам server, project, client и request. Вы можете также выполнять перенаправление и вызывать другие функции.

Функция ssjs_onError имеет следующий синтаксис:

function ssjs_onError (<message>,<file>,<line number>)

<message> текст сообщения об ошибке

<file> имя исходного файла

<line number> номер строки с ошибкой

Ошибка JavaScript в ходе выполнения функции onError записывается в log-файл и трассируется (если активна). Функция ssjs_onError, однако, не вызывается рекурсивно. Ошибка в функции onError вызывает запись сообщения в error log, но не выполняет вызов onError.

Вот пример функции:

function ssjs_onError(msg,file,line) { write("<br>\n<hr>") write("error message: "+msg+"<br>\n") write("file name: "+file+"<br>\n") write("line number: "+line+"<br>\n") write("<hr>") }

ПРИМЕЧАНИЕ:

Чтобы дать каждой странице её собственную специальную функцию onError, добавьте присвоение ssjs_onError в начале кода страницы. Например:

ssjs_onError = custom_onError; function custom_onError(msg,file,line) { // ... }

Серверный JavaScript выполняет всё, что ssjs_onError представляет во время ошибки. Вы можете использовать одну функцию ssjs_onError, которая совместно используется всеми страницами, либо можете динамически переключаться на другую функцию onError в любое время, в том числе в начале каждой страницы. Если два запроса выполняют одну и ту же функцию onError в один момент времени, они имеют различные среды выполнения, как если бы Вы одновременно выполняли какую-нибудь другую функцию.

Оглавление | Назад | Вперёд | Индекс

Дата последнего обновления: 29 сентября 1999 г.

© Copyright ╘ 1999 Sun Microsystems, Inc. Некоторая часть Copyright ╘ 1999 Netscape Communications Corp. Все Права Зарезервированы.