0
Backend разработка
Дмитрий Смаль
Что мы научимся делать?
●

Обрабатывать GET и POST запросы

●

Выводить HTML при помощи шаблонов

●

Хранить данные в СУБД...
Языки и интерфейсы
Статические (+/-):
●

СС++ модули к Web серверам.

●

Java – Servlets, ApplicationServers

Динамически ...
CGI
CGI
Запрос:
●

Параметры запроса – environ

●

Тело запроса – stdin

●

URI запроса – QUERY_STRING или argv[1]

Ответ:
●

...
CGI – окружение
Переменные окружения
REQUEST_METHOD – метод (GET, POST, …)
REQUEST_URI – строка запроса
QUERY_STRING - стр...
CGI скрипт
#!/usr/bin/python2.7
import os
import sys
print
print
print
print

"Content-type: text/html"
"Status: 200"
""
"...
nph - CGI скрипт
#!/usr/bin/python2.7
print
print
print
print

"HTTP/1.0 301 Found"
"Location: http://go.mail.ru/"
"Set-Co...
Обработка HTTP запросов
GET параметры
Гиперссылка
<a href=”/hello.cgi?name=me&greeting=hello”/>Hello!</a>

Переменная окружения
QUERY_STRING=name=...
POST параметры
Форма
<form method=”post” action=”/hello.cgi”>
<input name=”name” value=”me”/>
<input name=”greeting” value...
Файлы и не-ASCII
multipart/form-data
<form method=”post” action=”/hello.cgi”
enctype=”multipart/form-data”>
<input name=”n...
Библиотеки CGI
#!/usr/bin/python2.7
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
if “greeting” not in ...
Обработка форм
1) Валидация (regex, code)
if not re.match('[a-z]+', form[“name”]):
raise BaseException(“panic”)

2) Очистк...
Работа с базой данных
СУБД: таблицы
СУБД: SQL
INSERT INTO users (name, age)
VALUES ('petr', 10), ('masha', 25);
UPDATE users SET age = 10 WHERE name = 'petr';...
SQL в python
import MySQLdb
db = MySQLdb.connect(**options)
cursor = db.cursor()
cursor.execute(“update users set age = ag...
Конфигурация
Конфигурация
1) hardcode. Настройки зашиты в код приложения
2) script. Настройки представляют собой скрипт на
целевом ЯП
3...
Генерация HTML страниц
Шаблонизаторы
print “<html><body><h1>” 
“%s</h1></body></html>” % name

VS

context = {
'user' : get_user(form['name']),
'...
Шаблоны
<body>
<h1>{{ user.name }}</h1>
{% if user.sex == 'male' %}
<h2>{{ user.age }}</h2>
{% endif %}
{% for f in friend...
Структура страницы
Подшаблоны
{% include 'inc/header.html' %}
<table><tr>
<td>{% include 'inc/left.html' %}</td>
<td> CONTENT </td>
<td>{% in...
Наследование (layouts)
<!-- base.html -->
<div>{% block header %} HEADER {% endblock %}</div>
<table><tr>
<td>LEFT</td>
<t...
Наследование (layouts)
<!-- page.html –->
{% extends 'base.html' %}
{% block header %}
Custom header
{% endblock %}
{% blo...
Задача 1.
Листинг объектов
Листинг объектов
1) Параметры: фильтрация, сортировка, номер страницы
2) /images/?order=created&page=3&limit=10
3) Результ...
Листинг объектов
#!/usr/bin/python
import cgi
import psycopg2
import settings
db = psycopg2.connect(**settings.db)
cursor ...
Листинг объектов
context = {}
context['images'] = cursor.fetchall()
cursor.execute('select count(*) as cnt from images')
t...
Paginator
Аргументы: total, page, limit
Результат:
{
'total': 100, 'page': 5, 'limit': 10,
'next_page': 6, 'prev_page': 4,...
Задача 2.
Изменение объекта
Изменение объекта
1) Два режима работы: отображение формы и
обновление объекта
2) Разделение по методу HTTP (GET | POST). ...
Изменение объекта
#!/usr/bin/python
import cgi; import psycopg2; import settings; import os
db = psycopg2.connect(**settin...
Изменение объекта
<form method=”POST” action=”/cgi-bin/object”>
{% if res %}
<p style=”color: green”>Объект обновлен:{{ re...
Best Practice
1) Разделять методы GET – получение, POST – обновление
данных
2) Сообщать об ошибках и успехе
3) Коды возвра...
Задача 3.
Wizard
Wizard
1) Statefull vs Stateless.
2) Как передать данные между страницами?
выбор товара → информация о клиенте
→ место дос...
Скрытые поля
<!-- page2.html →
<form method=”POST” action=”/page3.html”>
<input type=”hidden” name=”item_id” value=”1”>
<i...
Cookie и Сессии
Cookie:
Set-Cookie: name=val; path=/; domain=domain.ru;
expires=Tue, 20 Mar 2012 11:52:54 GMT
Cookie: name...
Cookie в Python
Установка:
import Cookie
cookie = Cookie.SimpleCookie()
cookie['name'] = 'val'
cookie['name']['path'] = '/...
Достоинства CGI
1) простая концепция “скриптов”
2) стандарт – поддержка на любом хостинге
3) последовательное исполнение
Недостатки CGI
1) смешение кода и HTML → шаблонизаторы
2) повторение логики → вынесение кода в библиотеки
3) pretty urls →...
WSGI – pep 3333
def application(environ, start_response):
start_response('200 OK', [
('Content-Type', 'text/plain')
])
yie...
Спасибо за внимание
Дмитрий Смаль, smal@corp.mail.ru
Upcoming SlideShare
Loading in...5
×

Web весна 2013 лекция 4

162

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
162
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
6
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Web весна 2013 лекция 4"

  1. 1. Backend разработка Дмитрий Смаль
  2. 2. Что мы научимся делать? ● Обрабатывать GET и POST запросы ● Выводить HTML при помощи шаблонов ● Хранить данные в СУБД Типичные задачи ● Отображение списка объектов ● Изменение (редактирование) объектов ● Wizards: последовательности страниц
  3. 3. Языки и интерфейсы Статические (+/-): ● СС++ модули к Web серверам. ● Java – Servlets, ApplicationServers Динамически (+/-): ● Perl – CGI, mod_perl, PSGI ● PHP – mod_php, FastCGI (FPM) ● Ruby – rack, свой сервер (mongrel) ● Python – WSGI, свой сервер (Tornado) ● JavaScript – свой сервер (NodeJS)
  4. 4. CGI
  5. 5. CGI Запрос: ● Параметры запроса – environ ● Тело запроса – stdin ● URI запроса – QUERY_STRING или argv[1] Ответ: ● Тело ответа (с заголовками) - stdout ● Ошибки выполнения - stderr ● HTTP код – через псевдозаголовок Status
  6. 6. CGI – окружение Переменные окружения REQUEST_METHOD – метод (GET, POST, …) REQUEST_URI – строка запроса QUERY_STRING - строка параметров REMOTE_ADDR – ip адрес клиента SCRIPT_NAME – имя текущего скрипта HTTP_COOKIE – заголовок Cookie: HTTP_REFERER – заголовок Referer:
  7. 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. 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 ?
  9. 9. Обработка HTTP запросов
  10. 10. GET параметры Гиперссылка <a href=”/hello.cgi?name=me&greeting=hello”/>Hello!</a> Переменная окружения QUERY_STRING=name=me&greeting=hello CGI скрипт get_params = {} qs = os.environ['QUERY_STRING'] for pair in qs.split('&'): key, value = pair.split('=') get_params[key] = value
  11. 11. POST параметры Форма <form method=”post” action=”/hello.cgi”> <input name=”name” value=”me”/> <input name=”greeting” value=”hi”/> <input type=”submit”/> </form> Стандартный поток ввода STDIN name=me&greeting=hello CGI скрипт qs = sys.stdin.read() ...
  12. 12. Файлы и не-ASCII multipart/form-data <form method=”post” action=”/hello.cgi” enctype=”multipart/form-data”> <input name=”name” value=”me”/> <input name=”pic” type=”file”/> <input type=”submit”/> </form> URI percent encoding <a href=”/hello.cgi?name=%D0%B8%D0%BC%D1%8F”>привет</a>
  13. 13. Библиотеки CGI #!/usr/bin/python2.7 import cgi import cgitb cgitb.enable() form = cgi.FieldStorage() if “greeting” not in form: raise BaseException(“can't work”) greeting = form[“greeting”] names = form.getlist(“name”) pic = forms[“pic”].file.read()
  14. 14. Обработка форм 1) Валидация (regex, code) if not re.match('[a-z]+', form[“name”]): raise BaseException(“panic”) 2) Очистка story = re.sub('<[^>]+>', ' ', form[“story”]) 3) Экранирование story = form[“story”] re.sub('<', '&lt;', story) re.sub('>', '&gt', story)
  15. 15. Работа с базой данных
  16. 16. СУБД: таблицы
  17. 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. 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()
  19. 19. Конфигурация
  20. 20. Конфигурация 1) hardcode. Настройки зашиты в код приложения 2) script. Настройки представляют собой скрипт на целевом ЯП 3) YAML, XML, ini, Config::Apache 4) Переменные, разделение на несколько файлов
  21. 21. Генерация HTML страниц
  22. 22. Шаблонизаторы print “<html><body><h1>” “%s</h1></body></html>” % name VS context = { 'user' : get_user(form['name']), 'friends' : get_friends(form['name']) } print render('tpl/home.html', context)
  23. 23. Шаблоны <body> <h1>{{ user.name }}</h1> {% if user.sex == 'male' %} <h2>{{ user.age }}</h2> {% endif %} {% for f in friends %} <a href=”mailto:{{ f.email }}”>{{ f.name }}</a> <p>{{ f.about|linebreaks }}</p> {% endfor %} </body>
  24. 24. Структура страницы
  25. 25. Подшаблоны {% include 'inc/header.html' %} <table><tr> <td>{% include 'inc/left.html' %}</td> <td> CONTENT </td> <td>{% include 'inc/right.html' %}</td> </tr></table> {% include 'inc/footer.html' %}
  26. 26. Наследование (layouts) <!-- base.html --> <div>{% block header %} HEADER {% endblock %}</div> <table><tr> <td>LEFT</td> <td>{% block content %} CONTENT {% endblock %}</td> <td>RIGHT</td> </tr></table> <div>{% block footer %} FOOTER {% endblock %}</div>
  27. 27. Наследование (layouts) <!-- page.html –-> {% extends 'base.html' %} {% block header %} Custom header {% endblock %} {% block content %} <h1>{{ user.name }}</h1> <div>{{ block.super }}</div> {% endblock %}
  28. 28. Задача 1. Листинг объектов
  29. 29. Листинг объектов 1) Параметры: фильтрация, сортировка, номер страницы 2) /images/?order=created&page=3&limit=10 3) Результат работы скрипта: список объектов для данной страницы и paginator 4) paginator – представляет положение в списке страниц
  30. 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. 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)
  32. 32. Paginator Аргументы: total, page, limit Результат: { 'total': 100, 'page': 5, 'limit': 10, 'next_page': 6, 'prev_page': 4, 'next_page10': 10, 'prev_page10': 1, 'first_page':1, 'last_page': 10, 'pages' : [3, 4, 5, 6, 7] }
  33. 33. Задача 2. Изменение объекта
  34. 34. Изменение объекта 1) Два режима работы: отображение формы и обновление объекта 2) Разделение по методу HTTP (GET | POST). Кеширование запросов 3) Использование спец. параметра (action) 4) Отображение ошибок и результата действия
  35. 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. 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. 37. Best Practice 1) Разделять методы GET – получение, POST – обновление данных 2) Сообщать об ошибках и успехе 3) Коды возврата при ошибке и успехе 4) Проверять данные пользователя а) на сервере – безопасность программы б) на клиенте – удобство пользователя 5) Выделять неправильно введеные поля
  38. 38. Задача 3. Wizard
  39. 39. Wizard 1) Statefull vs Stateless. 2) Как передать данные между страницами? выбор товара → информация о клиенте → место доставки → подтверждение 3) Варианты: - через URL - через скрытые поля - через Cookie - через сессии
  40. 40. Скрытые поля <!-- page2.html → <form method=”POST” action=”/page3.html”> <input type=”hidden” name=”item_id” value=”1”> <input type=”hidden” name=”ammount” value=”4”> <input type=”text” name=”name” value=””> <input type=”text” name=”phone” value=””> <input type=”submit”> </form>
  41. 41. Cookie и Сессии Cookie: Set-Cookie: name=val; path=/; domain=domain.ru; expires=Tue, 20 Mar 2012 11:52:54 GMT Cookie: name=val;name2=val2;is_visited=2011-13-15 Сессии: 1) Ключ сессии – в cookie 2) Данные – на сервере (memcached, database, files)
  42. 42. Cookie в Python Установка: import Cookie cookie = Cookie.SimpleCookie() cookie['name'] = 'val' cookie['name']['path'] = '/path' Получение: import Cookie cookie = Cookie.SimpleCookie() cookie.load('a=b;c=d') for name in cookie: print '%s => %s' % (name, cookie[name])
  43. 43. Достоинства CGI 1) простая концепция “скриптов” 2) стандарт – поддержка на любом хостинге 3) последовательное исполнение
  44. 44. Недостатки CGI 1) смешение кода и HTML → шаблонизаторы 2) повторение логики → вынесение кода в библиотеки 3) pretty urls → RewriteEngine 4) производительность (fork, exec, parse, db.connect) → кеширование кода (FastCGI, mod_perl etc)
  45. 45. WSGI – pep 3333 def application(environ, start_response): start_response('200 OK', [ ('Content-Type', 'text/plain') ]) yield 'Hello Worldn' def application(environ, start_response): start_response('200 OK', [ ('Content-Type', 'text/plain')]) return [ 'Hello Worldn' ]
  46. 46. Спасибо за внимание Дмитрий Смаль, smal@corp.mail.ru
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×