ЛАБОРАТОРНАЯ РАБОТА №10

Тема: Использование технологии AJAX при разработке клиент-серверного приложения

Цель: Рассмотрение особенностей работы серверного приложения, использующего технологию AJAX

ОГЛАВЛЕНИЕ

1 Использование технологии AJAX
1.1 Объект XMLHttpRequest
1.2 Чтение текста из локального сервера
1.3 Обеспечение безопасности и конфиденциальности данных в сети
2 Разработка приложения с использованием технологии AJAX
2.1 Разработка клиентской части
2.2 Разработка серверной части
2.2.1 Разработка тестов
2.2.2 Разработка тестирующей программы
2.2.3 Передача результатов тестирования
Пример №1
Пример №1a
Пример №1b
Пример №1c
Пример №2
Индивидуальные задания

 Оглавление

1 Использование технологии AJAX

AJAX (от англ. Asynchronous Javascript and XML) – асинхронный JavaScript и XML) представляет собой технологию, позволяющую при необходимости в фоновом режиме (не прерывая работы пользователя и незаметно для него) выполнять запросы к серверу и получать дополнительные данные для обновления отдельных частей Web-страницы, тем самым исключая необходимость повторной загрузки страницы. Например, выполнять на стороне сервера проверку правильности заполнения данных пользоваетелем по мере их ввода.
Без использования технологии AJAX для решения этой задачи имеются такие возможности:

В целом использование AJAX имеет следующие преимущества:

Недостатки использования AJAX:

Для применения AJAX необходимы следующие компоненты:

Первоначально технологию AJAX разработала фирма Microsoft в виде объекта ActiveX для браузера Internet Explorer. Затем программисты проекта Mozilla создали объект XMLHttpRequest с (почти) идентичными API, который после доработки стандартизирован организацией W3C и в настоящее время поддерживается всеми ведущими браузерами. Последнее обновление действующего стандарта XMLHttpRequest (Living Standart) произошло 25.11.2015 года.
Технология AJAX стала популярной в 2005 году в связи с появлением сервиса Google Suggest (англ. suggest – предлагать) – технологии автозаполнения строки поискового запроса на основе общей статистики самых популярных запросов. Таким образом, запрос пользователя предсказывается после ввода уже нескольких символов, и в выпадающем списке предлагается выбор готовых слов и словосочетаний.

 Оглавление

1.1 Объект XMLHttpRequest

Объект XMLHttpRequest дает возможность отправлять асинхронные HTTP-запросы из кода JavaScript серверу, принимать от него ответы и обновлять отдельные части Web-страницы, не прерывая работу пользователя. Имеет следующие методы:

и свойства:

Во время функционирования объекта XMLHttpRequest при изменении его состояния (которое указывается в свойстве readyState) возникает событие onreadystatechange, которое может быть использовано для определения текущего состояния объекта.
Кроме того современная спецификация предусматривает следующие события оазвития (progress events), т.е. возникающие по ходу обработки запроса:

Для создания экземпляров объекта XMLHttpRequest при использовании браузеров, которые его поддерживают – все бразеры, за исключением IE5 и IE6, необходимо использовать конструктор XMLHttpRequest(), а для браузеров Internet Explorer версий 5 и 6 – конструктор ActiveXObject("Microsoft.XMLHttp"). Поэтому для создания объекта xhr, который имеет все методы и свойства объекта XMLHttpRequest, можно предложить следующий код:

var xhr;
if(window.XMLHttpRequest) {
xhr=new XMLHttpRequest();
} else {
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}

Создание объекта xhr, использование его методов, свойств и обработчиков событий приведено в примерах №1, №1a и №1b, в которых осуществлен прием текстовых данных из локального сервера, а также в примере №2, в котором в процессе тестирования выполнена передача серверу имени тестируемого, прием тестов от сервера и передача ответов серверу.

 Оглавление

1.2 Чтение текста из локального сервера

В примере №1 показано чтение текстового файла из локального сервера с помощью технологии AJAX. Особенностью этого примера является то, что в нем, помимо решения основной задачи – получения текстовых данных из сервера и вывода их на текущей странице, решаются также задачи получения и вывода дополнительной информации учебного и отладочного характера:

 Оглавление

Пример 1

<!DOCTYPE html>
<html>
<head>
<title> Чтение текста из локального сервера с помощью технологии AJAX</title>
</head>
<body>
<div id="myDiv" />
<script>
var myDiv=document.getElementById("myDiv");
var xhr;
if(window.XMLHttpRequest) {
xhr=new XMLHttpRequest();
} else { // IE5,IE6
xhr=new ActiveXObject("Microsoft.XMLHTTP");
}
myDiv.innerHTML="Состояние 0 (UNSENT): Объект xhr создан; <br>";
xhr.open("GET", "http://zykov/data.txt?r="+Math.random(),true);
xhr.onreadystatechange=handleStateChange;
xhr.send() ;
myDiv.innerHTML+="Скрипт продолжает работать<br>";
function handleStateChange() {
switch(this.readyState) {
case 1: myDiv.innerHTML+=
"Состояние 1 (OPEND): Метод open() успешно вызван; <br>";break;
case 2: myDiv.innerHTML+=
"Состояние 2 (HEADERS RECEIVED): получены HTTP-заголовки ответа :<br>"+
"Content-Type: <span style='color:blue'>"+ this.getResponseHeader("Content-Type")+
"</span<br>"+
"Date: <span style='color:blue'>"+ this.getResponseHeader("Date")+ "</span> "+
this.statusText+ "<br>"; break;
case 3: myDiv.innerHTML+=
"Состояние 3 (LOADING): тело ответа получено; "+this.statusText+"<br>"; break;
case 4: { myDiv.innerHTML+=
"Состояние 4 (DONE) передача данных завершена "+ this.statusText+"<br>";
if(this.status==200) {
try {
resp=this.responseText;
myDiv.innerHTML+="Сервер передал:
<span style='color:blue; font-size:5.5mm'>"+resp+"</span><br>";
}
catch(e) {
myDiv.innerHTML+="Ошибка чтения ответа: "+e.name.toString()+" "+
e.message;
}
} else myDiv.innerHTML+="Ошибка получения данных: статус: "+this.status;
}
}
}
</script>
</body>
</html>

При запуске примера №1 выполняются следующие действия:

Отметим, что использование в методе open() аргумента URL, имеющего значениее "http://zykov/data.txt?r="+Math.random(), позволяет передать на сервер не только url-адрес текстового файла, но и случайное число, генерируемое методом random() объекта Math. Поскольку при этом каждый вызов будет отличаться от предыдущего, браузер будет передавать клиенту данные не из своего кэша, а непостредственно из сервера. Этот режим можно использовать, например, при отладке скрипта для разных значений данных на сервере.
При каждом изменении состояния запроса (свойство readyState), начиная с состояния 1, происходит вызов функции handleStateChange(), которая осуществляет такие действия:

При выполнении примера №1 в окно браузера были выведены следующие результаты его работы:

Состояние 0 (UNSENT): Объект xhr создан;
Состояние 1 (OPEND): Метод open() успешно вызван;
Скрипт продолжает работать
Состояние 2 (HEADERS RECEIVED): получены HTTP-заголовки ответа :
Content-Type: text/plain
Date: Fri, 11 Dec 2015 15:33:34 GMT OK
Состояние 3 (LOADING): тело ответа получено; OK
Состояние 4 (DONE) передача данных завершена OK
Сервер передал: Привет, клиент!

В случае выполнения примера №1 в синхронном режиме (async=false) были получены следующие результаты его работы:

Состояние 0 (UNSENT): Объект xhr создан;
Состояние 4 (DONE) передача данных завершена OK
Сервер передал: Привет, клиент!
Скрипт продолжает работать

Эти результаты работы в синхронном режиме показывают следующее:

Поэтому синхронный режим в дальнейшем использоваться не будет.
В примере №1a решается та же задача, что и в примере №1 – получение данных из текстового файла сервера. Но в нем, в отличие от примера №1 не задействованы средства пояснения и отладки – это пример уже отлаженного скрипта, поэтому объем его кода значительно меньше:

 Оглавление

Пример 1a

<!DOCTYPE html>
<html>
<head>
<title> Чтение текста из локального сервера</title>
</head>
<body>
<div id="myDiv" />
<script>
var myDiv=document.getElementById("myDiv");
var xhr=new XMLHttpRequest();
xhr.open("get", "http://zykov/data.txt?r="+Math.random());
xhr.onreadystatechange=handleReadyState;
xhr.send();
function handleReadyState() {
if(this.readyState==this.DONE&&this.status==200) {
myDiv.innerHTML+="<span style='color:blue; font-size:5.5mm'>"+ this.responseText+
"</span>";
}
}
</script>
</body>
</html>

Результат работы примера №1a:

Привет, клиент!

Пример №1b отличается от примера №1a тем, что в нем использованы возможности, указанные в новой спецификации объекта XMLHttpRequest (см. подраздел 1.1), а именно:


 Оглавление

Пример 1b

<!DOCTYPE html>
<html>
<head>
<title> Чтение текста из локального сервера</title>
</head>
<body>
<div id="myDiv" />
<script>
var myDiv=document.getElementById("myDiv");
var xhr=new XMLHttpRequest();
xhr.open("get", "http://zykov/data.txt?r="+Math.random());
xhr.onerror=function(e) {
myDiv.innerHTML+=" Error";
}
xhr.onload=function() {
myDiv.innerHTML+="<span style='color:blue; font-size:5.5mm'>"+ this.response+
"</span>";
}
xhr.send();
</script>
</body>
</html>

Результат работы примера №1b такой же, как результат работы примера №1a:

Привет, клиент!

Отметим, что в примере №1b вместо события load можно использовать событие progress и получать данные по частям (пакетам). Но в данном случае данные из сервера имеют небольшой размер и результат работы будет такой же, как и при использовании события load:

Привет, клиент!

Необходимо сказать, что приведенные результаты работы примеров №1, №1a и №1b были получены только при использовании браузера Internet Explorer. На остальных ведущих браузерах примеры №1 и №1a не дадут никакого разультата, а пример №1b даст сообщение "Error". Это связано с несколько различной трактовкой браузерами политики "одинакового произхождения" ("the same origin"), которая была введена для междоменных передач данных с целью повышения их безопастности, и которую поддерживает технология AJAX (см. подраздел 1.3).

 Оглавление

1.3 Обеспечение безопасности и конфиденциальности данных в сети

С целью обеспечения безопасности и конфиденциальности данных при их обмене в сети были разработаны правила, названные "политикой одинакового источника" (same-origin policy). Две Web-страницы имеют одинаковый источник, если:

Пусть, например, Web-страница имеет следующий URL: http://www.company.com/dir/page.html. Тогда результаты проверки на одинаковый источник следующих страниц дадут такие результаты:

Знак "+" означает, что проверяемая страница имеет одинаковый источник с исходной страницей, а знак "-" – разный.
Политика same-origin предусматривает, что две Web-страницы могут обмениваться данными без ограничений только при условии, что они имеют одинаковый источник. Отметим, что браузер Internet Explorer имеет два исключения из этого правила:

Поскольку объект XMLHttpRequest() подчиняется политике одинакового источника, то при доступе к данным локального сервера просходит сравнение происхождения страницы, вызвавшей запрос, и сервера, отправляющего ответ браузеру. И хотя в примерах №1, №1a и №1b скрипты, формирующие запросы к серверу, и сам сервер распололагаются на одном и том же компьютере, считается, что они имеют разный источник, поскольку используют разные схемы. Поэтому браузер Internet Explorer, за счет исключения из общего правила, разрешил чтение данных из локального сервера, а браузеры, подчиняющиеся всем правилам политики одинакового источника, – нет.
Выходом из создавшегося положения является использование предложенного группой W3C механизма CORS (Cross-Origin Resource Sharing), т.е. совместное использование ресурсов при обмене, осуществляемом страницами разного источника (кросс-доменными страницами), который состоит из набора HTTP-заголовков и указывает Web-серверу путь, разрешающий доступ к требуемым ресурсам для определенных сайтов. Если сервер в своем ответе указывает HTTP-заголовок Access-Control-Allow-Origin со значениями "*", то это означает, что он разрешает доступ к данным сервера всем сайтам. Другое значение указывает имя сайта, для которого разрешен доступ. Отметим, что разрешение действует только для методов GET и POST, на методы PUT и DELETE оно не распространяется.
Таким образом, чтобы данные на сервере стали доступны объекту XMLHttpRequest(), необходимо, чтобы сервер в своем ответе наряду с данными передал HTTP-заголовок "Access-Control-Allow-Origin: *". Однако это можно сделать, только применив серверное приложение, например, следующий скрипт на языке Python

#!c:/ . . . /python.exe
print("Access-Control-Allow-Origin: *")
print()
print("Hello, client!"),

который расположен по адресу "http://zykov/PYTHON/data.py" и выполняет следующие действия:

Если в примере №1b изменить URL-адрес запрашиваемого ресурса с http://zykov/data.txt?r=' + Math.random() на http://zykov/PYTHON/data.py?r=' + Math.random(), то при запуске созданного таким образом примера №1c

 Оглавление

Пример 1c

<!DOCTYPE html>
<html>
<head>
<title> Чтение текста из локального сервера</title>
</head>
<body>
<div id="myDiv" />
<script>
var myDiv=document.getElementById("myDiv");
var xhr=new XMLHttpRequest();
xhr.open("get", "http://zykov/PYTHON/data.py?r="+Math.random());
xhr.onerror=function(e) {
myDiv.innerHTML+=" Error";
}
xhr.onload=function() {
myDiv.innerHTML+="<span style='color:blue; font-size:5.5mm'>"+ this.response+
"</span>";
}
xhr.send();
</script>
</body>
</html>

получим корректный результат:

Привет, клиент!

уже на всех популярных браузерах: Internet Explorer, Chrome, Firefox, Opera и Safari. Такие же результаты будут получены и при изменении метода GET на метод POST.

 Оглавление

2 Разработка приложения с использованием технологии AJAX

В качестве примера разработки приложения, использующего в рамках технологии "клиент-сервер" средства AJAX, выбрана задача тестирования пользователя на стороне клиента. Взаимодействие между клиентом и сервером осуществляется следующим образом.
Тестирование начинается с того, что клиент запрашивает имя пользователя и передает его серверу. Сервер последовательно тест за тестом отправляет клиенту сформированные и хранящиеся на сервере тесты. Клиент визуализирует тесты на Web-странице, принимает по каждому тесту ответ пользователя и передает его серверу. После окончания тестирования сервер передает клиенту результаты тестирования. Все обмены данными между сервером и клиентом происходят в рамках технологии AJAX, т.е. без формирования новых Web-страниц.
Далее мы рассмотрим более подробно работу клиенткой части приложения и работу ее серверной части.

 Оглавление

2.1 Разработка клиентской части

Клиентская часть приложения реализована в виде примера №2, при выполнении которого создается Web-страница, содержащая заголовок ("Тестирование"), кнопки "СТАРТ" и "ОТВЕТ", а также поле для помещения тестов (тег <div ... />. CSS свойства кнопок "Начать тестирование" и "Указать ответ" задаются из файла "lab.css", который подклюяается к HTML-файлу данного примера (см. раздел 2 лаб. раб. №7).

 Оглавление

Пример 2

<html>
<head>
<title>Тестирование пользователя с использованием технологии AJAX </title>
<link rel=stylesheet href="../lab.css">
<script>
var name='', answer='', //Фамилия и ответ пользователя
xhr=new XMLHttpRequest();
function subm1() {
name=prompt('Введите фамилию','');
if(name) {
xhr.open('GET','http://zykov/PYTHON/testing.py?r='+ Math.random()+'&name='+name);
xhr.send(null);
}
else alert("Имя не введено");
}
function subm2() {
answer=prompt('Введите ответ в виде трех двоичных цифр','');
if (answer) {
xhr.open('GET','http://zykov/PYTHON/testing.py?r='+ Math.random()+'&answer='+answer);
xhr.send(null);
}
else alert("Ответ не указан")
}
xhr.onerror=function(e) {
myDiv.innerHTML+=" Ошибка получения данных из сервера";
}
xhr.onload=function() {
myDiv=document.getElementById("div");
resp=this.responseText;
myDiv.innerHTML="<p><span style='color:blue;font-size:5.5mm'>"+resp+ "</span>";
}
}
</script>
</head>
<body>
<h1>Тестирование</h1>
<button onclick="subm1()">Начать <br>тестирование</button> 
<button onclick="subm2()">Указать <br>ответ</button>
<div id="div" />
</body>
</htnl>

 Оглавление

Пример №2 начинает свою работу с создания объекта xhr, реализующего механизм AJAX. Это делается с помощью конструктора XMLHttpRequest() без использования альтернативного варианта в виде конструктора ActiveXObject("Microsoft.XMLHTTP"), как это было выполнено в примере №1. Кроме того, с целью уменьшения объема скрипта не были использованы средства отладки и диагностики. При необходимости все эти программные стредства могут быть добавлены в код.
Процесс тестирования начинается с нажатия пользователем (тестируемым) кнопки "Начать тестирование". При этом по событию onclick происходит вызов функции submit1(), которая:

Затем с помощью обработчика события onerror() объекта xhr проверяется, не возникла ли ошибка при обмене данными между клиентом и сервером. Если ошибка возникла – клиенту выдается соответствующее сообщение и тестирование завершается.
При успешном завершении приема данных от сервера – по событию onload объекта xhr производится считывание данных, переданных сервером, в переменную resp с последующим отображением ее значения на данной Web-странице с помощью тега <div>.
Сервер в соответствии с работой серверного приложения (см. описание программы testing.py в подразделе 2.2.2) передает клиенту данные двух типов:

Когда сервер передает тест, пользователь формирует ответ на этот тест в виде трех двоичных цифр ( см. подраздел 2.2.1) и нажимает кнопку "Указать ответ". При этом по событию onclick происходит вызов функции submit2(), которая:

Если сервер передал вместо очередного теста результаты тестирования, то это обозначает, что процесс тестирования завершен. Чтобы выполнить тестирование нового пользователя или протестировать текущего пользователя еще раз, необходимо нажать кнопку "Начать тестирование".

 Оглавление

2.2 Разработка серверной части

2.2.1 Разработка тестов

Тесты предлагается формировать в виде строки, которая содержит:

Имеется несколько подходов к формированию вариантов ответа и эталонного значения. Например, из всех вариантов ответа только один вариант сделать правильным, а остальные – неправильными. Но при таком подходе и при трех вариантах ответа полуается слишком большая вероятность угадывания правильного ответа (1/3). Чтобы не увеличивать число вариантов ответа предлагается такой подход к формированию тестов.
Каждый из трех вариантов ответа может быть как правильным, так и неправильным. Если вариант правильный, он имеет значение 1, если нет – 0). Эталонное значение теста формируется из значений вариантов ответа в виде трех двоичных цифр: самой левой цифре соответствует значение первого варианта ответа, средней цифре – значение второго варианта ответа и правой цифре – значение третьего варианта ответа. Например, эталонное значение 101 означает, что первый и третий варианты ответа были правильными, а второй вариант – нет. При таком подходе вероятность угадать правильный ответ уменьшается до 1/8.
Для формирования тестов и записи их на диск разработана программа form_test.py, которая не является серверным приложением и может запускаться на выполнение из среды разработки Python:

import pickle
TESTS=[ 'Тест №1. Изменяемые типы данных:' \
'<br>1. кортеж<br> 2. словарь <br>3. строка;010' ,
'Тест №2. Выполняется только чтение из текстового файла:' \
'<br>1. mode=\'\' <br>2. mode=\'r\' <br>3. mode=\'r+\';110' ,
'Тест №3. Выполняется удаление существующего файла:' \
'<br>1. mode=\'w\' <br>2. mode=\'w+\' <br>3. mode=\'a\';100' ,
'Тест №4.В качестве ключа словаря могут быть использованы:' \
'<br>1. кортежи <br>2. числа <br>3. строки;111' ,
'Тест №5. Модуль mod имеет фукцию func(). При каком подключении модуля' \
'фукция func() будет непосредсвтвенно доступна программе?' \
'<br>1. import mod <br>2. from mod import func <br>3. from mod import *;011' ]

f= open ( 'tests.dat' , 'wb' )
pickle.dump(TESTS,f)
f.close()
print ( "It/s done" )

Таким образом в соответствии с выше описанным подходом сформировано пять тестов в виде списка строк TESTS, который с помощью метода dump() модуля pickle в сериализованном виде записан в двоичный файл tests.dat и в последствии может быть использован для получения тестов (см. подраздел 2.2.1).

 Оглавление

2.2.2 Разработка тестирующей программы

В качестве примера серверного приложения, осуществляющего AJAX-взаимодействие с клиентским приложением (см. пример №2 в подразделе 2.1) разработана программа testing.py:

#!c:/ . . . /python.exe
print ( "Access-Control-Allow-Origin: *" )
print ()
import cgi, cgitb, random, pickle
from my_mod import write_results, D
cgitb.enable()
def get_test (file_name): # Функция считывает из файла file_name тесты
f= open (file_name, 'rb' ) # и возвращает один из них
test_list=pickle.load(f)
f.close()
test=random.choice(test_list)
test_list.remove(test)
f= open ( 'cur_tests.dat' , 'wb' )
pickle.dump(test_list,f)
f.close()
return test

max_test=3
data=cgi.parse()
if 'name' in data:
# От клиента получено имя тестируемого
test=get_test( 'tests.dat' )
print (D, test.split( ';' )[0])
user_dict={ # Словарь данных тестируемого содержит:
'name' :data[ 'name' ][0], # имя
'number_test' :1, # порядковй номер очередного теста
'tests' :[test], # список переданных тестов
'answers' :[], # список ответов пользователя
'points' :0 } # число набранных баллов
f= open ( 'user.dat' , 'wb' )
pickle.dump(user_dict,f)
f.close()
if 'answer' in data:
# От клиента получен ответ тестируемого
f= open ( 'user.dat' , 'rb' )
user_dict=pickle.load(f)
user_dict[ 'answers' ]+=[data[ 'answer' ][0]]
tests=user_dict[ 'tests' ]
etalon=tests[ len (tests)-1:][0].split( ';' )[1]
if data[ 'answer' ][0]==etalon: user_dict[ 'points' ]+=1
if user_dict[ 'number_test' ]<'max_test:
test=get_test( 'cur_tests.dat' )
print (D, test.split( ';' )[0])
user_dict[ 'number_test' +=1
user_dict[ 'tests' +=[test]
f= open ( 'user.dat' , 'wb' )
pickle.dump(user_dict,f)
f.close()
else :
write_results(user_dict,out_points=1,out_tests=1,out_answers=1)

 Оглавление

В начале своей работы программа testing.py подключает необходимые ей для работы модули: cgi, cgitb, random, pickle и функцию write_results с константой D из модуля my_mod. После получения запроса от клиента программа преобразует, используя метод parse() модуля cgi, полученные данные в словарь data и осуществляет их анализ.
Если клиентская часть передала имя пользователя, т.е. словарь data содержит ключ "name", то выполняются следующие действия:

Если клиентская часть передает значение ответа пользователя, т.е. словарь полученных данных data содержит ключ "answers", то выполняются следующие действия:

Результаты тестирования:
Имя – Сидоров Евгений
Оценка – "Отлично"

 Оглавление

2.2.3 Передача результатов тестирования

Для передачи клиенту результатов проведенного тестирования разработана функция write_results():

def write_results (user_dict, out_points=0, out_tests=0, out_answers=0):
print (D, '<i><b>Результаты тестирования:</b></i>' ,
'<br>Имя &ndash; ' , user_dict[ 'name' ])
if out_points:
print ( '<br>Получено баллов &ndash; ' ,
user_dict[ 'points' ], ' из ' , user_dict[ 'number_test' ])
if out_tests:
print ( '<br>Тесты &ndash; ' )
for el in user_dict[ 'tests' ]: print (el.split( '.' )[0])
if out_answers:
print ( '<br>Ответы &ndash; ' )
for el in user_dict[ 'answers' ]: print (el)
print ( '<br>Оценка &ndash; ' )
m=user_dict[ 'points' ]
if m==0: mark= "Неудовлетворительно"
elif m==1: mark= "Удовлетворительно"
elif m==2: mark= "Хорошо"
else : mark= "Отлично"
print ( '"' , mark, '"' ],

которая имеет один обязательный параметр – словарь user_dict, содержающий следующие ключи, отражающие отдельные компоненты тестирования:

и необязательные (опциональные) параметры: out_points, out_tests и out_answers, которые указывают, надо ли передавать для вывода на стороне клиента значение соответствующей компоненты тестирования (значение 1), или нет (значение 0). По умолчанию все они имеют значение 0, т.е. если не указывать эти аргументы при вызове функции write_results(), то такие данные, как число проведенных тестов, список тестов, список ответов и число баллов выводиться не будут. Будет выведено только имя тестирующего и полученная им оценка (см. работу программы testing.py в подразделе 2.2.2).
Чтобы получить наиболее полную информацию о проведенном тестировании, нужно вызвать функцию write_results(), указав в ней значения всех необязательных аргументов, равными 1:

write_results(user_dict,out_points=1,out_tests=1,out_answers=1)

При этом клиенту будет передана информация в следующем виде:

Результаты тестирования:
Имя – Сидоров Евгений
Получено баллов – 3 из 3
Тесты – Тест №3 Тест №1 Тест №5
Ответы – 100 010 111
Оценка – " Хорошо "

 Оглавление

#!c:/Documents and Settings/ZYKOV/AppData/Local/Programs/Python/Python35-32/python.exe
print ( "Content-Type: text/html" )
print ()
import cgi, cgitb, pickle, random
from my_mod import write_results,D
cgitb.enable()
data=cgi.parse()
f=open('all_users.dat','rb')
if "name" in data:
if data["name"][0]=='all':
print(D,'all')
while True:
try:
user_dict=pickle.load(f)
write_results(user_dict,points=1, tests=1, answers=1)
except EOFError: break
else:
found=False
while True:
try:
user_dict=pickle.load(f)
if user_dict["name"]==data["name"][0]:
write_results(user_dict,points=1,tests=1,answers=1)
found=True
except EOFError:
if not found:
print(D,data["name"][0],": Результаты тестироемого не найдены")
break
f.close()

Индивидуальные задания

Разработать приложение на базе технологий "клиент-сервер" и AJAX, осуществляющее тестирование пользователя на стороне клиента.
Клиентскую часть реализовать в виде HTML-документа с включенными фрагментами JavaScript, задачами которого являются:

В задачи серверной части приложения входит:

Таблица 1 – Параметры индивидуальных заданий

Номер
п/п
Ввод
имени
Ввод
ответов
Вывод
тестов
Тема
тестов
Правило
тестов
Данные
словаря
1<input>prompt()prompt()1)1)2)
2<input>prompt()<div />2)2)3)
3prompt()<input><div />3)3)1)
4<input>prompt()prompt()4)1)2)
5<input>prompt()<div />5)2)3)
6prompt()<input><div />6)3)1)
7<input>prompt()prompt()7)1)2)
8<input>prompt()<div />1)2)3)
9prompt()<input><div />2)3)1)
10<input>prompt()prompt()3)1)2)
11<input>prompt()<div />4)2)3)
12prompt()<input><div />5)3)1)
13<input>prompt()prompt()6)1)2)
14<input>prompt()<div />7)2)3)
15prompt()<input><div />1)3)1)
16<input>prompt()prompt()2)1)2)
17<input>prompt()<div />3)2)3)
18prompt()<input><div />4)3)1)
19<input>prompt()prompt()5)1)2)
20<input>prompt()<div />6)2)3)

 Оглавление