2. Что мы научимся делать?
●
Обрабатывать GET и POST запросы
●
Выводить HTML при помощи шаблонов
●
Хранить данные в СУБД
Типичные задачи
●
Отображение списка объектов
●
Изменение (редактирование) объектов
●
Wizards: последовательности страниц
3. Языки и интерфейсы
Статические (+/-):
●
СС++ модули к Web серверам.
●
Java – Servlets, ApplicationServers
Динамически (+/-):
●
Perl – CGI, mod_perl, PSGI
●
PHP – mod_php, FastCGI (FPM)
●
Ruby – rack, свой сервер (mongrel)
●
Python – WSGI, свой сервер (Tornado)
●
JavaScript – свой сервер (NodeJS)
5. CGI
Запрос:
●
Параметры запроса – environ
●
Тело запроса – stdin
●
URI запроса – QUERY_STRING или argv[1]
Ответ:
●
Тело ответа (с заголовками) - stdout
●
Ошибки выполнения - stderr
●
HTTP код – через псевдозаголовок Status
6. CGI – окружение
Переменные окружения
REQUEST_METHOD – метод (GET, POST, …)
REQUEST_URI – строка запроса
QUERY_STRING - строка параметров
REMOTE_ADDR – ip адрес клиента
SCRIPT_NAME – имя текущего скрипта
HTTP_COOKIE – заголовок Cookie:
HTTP_REFERER – заголовок Referer:
7. CGI скрипт
#!/usr/bin/python2.7
import os
import sys
print
print
print
print
"Content-type: text/html"
"Status: 200"
""
"<h1>Hello, world!</h1>"
for k, v in os.environ.items():
print "%s = %s<br>" % (k, v)
print >> sys.stderr, "Nice to meet you"
8. nph - CGI скрипт
#!/usr/bin/python2.7
print
print
print
print
"HTTP/1.0 301 Found"
"Location: http://go.mail.ru/"
"Set-Cookie: name=value"
""
Как сервер определяет nph скрипт ?
●
По имени файла nph-
●
По первой строчке вывода скрипта
В чем отличие от обычных CGI ?
17. СУБД: SQL
INSERT INTO users (name, age)
VALUES ('petr', 10), ('masha', 25);
UPDATE users SET age = 10 WHERE name = 'petr';
DELETE FROM users WHERE name = 'masha';
SELECT * FROM users WHERE age > 10;
SELECT * FROM users WHERE name = 'masha';
SELECT max(age) FROM users;
18. SQL в python
import MySQLdb
db = MySQLdb.connect(**options)
cursor = db.cursor()
cursor.execute(“update users set age = age+1 ”
”where name = ?”, form[“name”])
context = {}
cursor.execute(“select * from users”)
context['friends'] = cursor.fetchall()
cursor.execute(“select * from users where name = ?”,
form[“name”])
context['user'] = cursor.fetchone()
db.close()
20. Конфигурация
1) hardcode. Настройки зашиты в код приложения
2) script. Настройки представляют собой скрипт на
целевом ЯП
3) YAML, XML, ini, Config::Apache
4) Переменные, разделение на несколько файлов
29. Листинг объектов
1) Параметры: фильтрация, сортировка, номер страницы
2) /images/?order=created&page=3&limit=10
3) Результат работы скрипта: список объектов для данной
страницы и paginator
4) paginator – представляет положение в списке страниц
30. Листинг объектов
#!/usr/bin/python
import cgi
import psycopg2
import settings
db = psycopg2.connect(**settings.db)
cursor = db.cursor()
form = cgi.FieldStorage()
order = form.getfirst('order', 'created')
if order not in ('created', 'size'):
raise BaseException('oops')
page = int(form.getfirst('page', 1))
limit = int(form.getfirst('limit', 10))
sql = 'select * from img order by %s limit %d offset %d'
% (order, limit, limit * (page – 1))
cursor.execute(sql)
31. Листинг объектов
context = {}
context['images'] = cursor.fetchall()
cursor.execute('select count(*) as cnt from images')
total = cursor.fetchone()[0]['cnt']
context['pager'] = calc_paginator(total, page, limit)
db.close()
print
print
print
print
“Status: 200”
“Content-Type: text/html”
“”
render('/images.html', context)
34. Изменение объекта
1) Два режима работы: отображение формы и
обновление объекта
2) Разделение по методу HTTP (GET | POST). Кеширование
запросов
3) Использование спец. параметра (action)
4) Отображение ошибок и результата действия
35. Изменение объекта
#!/usr/bin/python
import cgi; import psycopg2; import settings; import os
db = psycopg2.connect(**settings.db)
cursor = db.cursor()
form = cgi.FieldStorage()
if os.environ['HTTP_METHOD'] == 'POST”:
try:
cursor.execute('update users set name = ? where id = ?',
form['name'], form['id'])
redirect('/cgi-bin/object?id=%s&res=updated' % form['id'])
catch BaseException, e:
redirect('/cgi-bin/object?id=%s&fail=fail' % form['id'])
else:
context = {}
cursor.execute('select * from users where id = ?', form['id'])
context['object'] = cursor.fetchone()
render('object.html', context)
36. Изменение объекта
<form method=”POST” action=”/cgi-bin/object”>
{% if res %}
<p style=”color: green”>Объект обновлен:{{ res }}</p>
{% endif %}
{% if fail %}
<p style=”color: red”>Ошибка: {{ fail }}</p>
{% endif %}
<input type=”hidden” name=”id”
value=”{{ object.id }}”>
<input type=”text” name=”name”
value=”{{ object.name }}”>
<input type=”submit”>
</form>
37. Best Practice
1) Разделять методы GET – получение, POST – обновление
данных
2) Сообщать об ошибках и успехе
3) Коды возврата при ошибке и успехе
4) Проверять данные пользователя
а) на сервере – безопасность программы
б) на клиенте – удобство пользователя
5) Выделять неправильно введеные поля
39. Wizard
1) Statefull vs Stateless.
2) Как передать данные между страницами?
выбор товара → информация о клиенте
→ место доставки → подтверждение
3) Варианты:
- через URL
- через скрытые поля
- через Cookie
- через сессии