36
Backend разработка Смаль Дмитрий [email protected]

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

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Web весна 2012 лекция 4

Backend разработка

Смаль Дмитрий[email protected]

Page 2: Web весна 2012 лекция 4

Что мы научимся делать? Обрабатывать GET и POST запросы Выводить HTML при помощи шаблонов Хранить данные в СУБД

Типичные задачи

Отображение списка объектов Изменение (редактирование) объектов Wizards: последовательности страниц

Page 3: Web весна 2012 лекция 4

Языки и технологии

Статические (+/-):

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

Java – Servlets, ApplicationServers

Динамически (+/-):

Perl – CGI, mod_perl, PSGI

PHP – mod_php, FastCGI (FPM)

Ruby – rack, свой сервер (mongrel)

Python – WSGI, свой сервер (Tornado)

JavaScript – свой сервер (NodeJS)

Page 4: Web весна 2012 лекция 4

CGI скрипт#!/usr/bin/python2.7

print "Content-type: text/html"

print "Status: 200"

print ""

print "<h1>Hello, world!</h1>"

import os

import sys

for k, v in os.environ.items():

print "%s = %s<br>" % (k, v)

print >> sys.stderr, "Nice to meet you"

Page 5: Web весна 2012 лекция 4

NPH - CGI скрипт

#!/usr/bin/python2.7

print "HTTP/1.0 301 Found"

print "Location: http://go.mail.ru/"

print "Set-Cookie: name=value"

print ""

Page 6: Web весна 2012 лекция 4

Передача GET параметров<a href=”/hello.cgi?

name=me&greeting=hello”/>Say hello</a>

QUERY_STRING=name=me&greeting=hello

get_params = {}

qs = os.environ['QUERY_STRING']

for pair in qs.split('&'):

key, value = pair.split('=')

get_params[key] = value

Page 7: Web весна 2012 лекция 4

Передача 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

import sys

qs = sys.stdin.read()

Page 8: Web весна 2012 лекция 4

Передача файлов и не-ASCII<form method=”post” action=”/hello.cgi”

enctype=”multipart/form-data”>

<input name=”name” value=”me”/>

<input name=”pic” type=”file”/>

<input type=”submit”/>

</form>

<a href=”/hello.cgi?name=Boris&name=Ivan”>здорово</a>

<a href=”/hello.cgi?name=%D0%B8%D0%BC%D1%8F”>привет</a>

Page 9: Web весна 2012 лекция 4

CGI библиотеки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()

Page 10: Web весна 2012 лекция 4

Обработка входных данных

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)

Page 11: Web весна 2012 лекция 4

Шаблонизаторы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)

Page 12: Web весна 2012 лекция 4

Шаблоны<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>

Page 13: Web весна 2012 лекция 4

Структура страницы

Page 14: Web весна 2012 лекция 4

Подшаблоны (includes)

{% 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' %}

Page 15: Web весна 2012 лекция 4

Наследование (layouts)

<!-- base.html -->

<div>HEADER</div>

<table><tr>

<td>LEFT</td>

<td>

{% block content %} CONTENT {% endblock %}</td>

<td>RIGHT</td>

</tr></table>

<div>FOOTER</div>

Page 16: Web весна 2012 лекция 4

Наследование (layouts)

<!-- page.html –->

{% extends 'base.html' %}

{% block content %}

<h1>{{ user.name }}</h1>

<div>{{ block.super }}</div>

{% endblock %}

Page 17: Web весна 2012 лекция 4

СУБД, SQL

INSERT

UPDATE

DELETE

SELECT

Page 18: Web весна 2012 лекция 4

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;

Page 19: Web весна 2012 лекция 4

Использование SQL в pythonimport 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()

Page 20: Web весна 2012 лекция 4

Конфигурация приложений

1) hardcode. Настройки зашиты в код приложения

2) script. Настройки представляют собой скрипт на целевом ЯП

3) YAML, XML, ini, Config::Apache

4) Переменные, разделение на несколько файлов

Page 21: Web весна 2012 лекция 4

Задача №1. Листинг объектов

1) Параметры: фильтрация, сортировка, номер страницы

2) /images/?order=created&page=3&limit=10

3) Результат работы скрипта: список объектов для данной страницы и paginator

4) paginator – представляет положение в списке страниц

Page 22: Web весна 2012 лекция 4

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 = form.getfirst('page', 1)

limit = form.getfirst('limit', 10)

sql = 'select * from images order by %s limit %d offset %d' % (order, limit, limit * (page – 1))

Page 23: Web весна 2012 лекция 4

cursor.execute(sql)

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 “Status: 200”

print “Content-Type: text/html”

print “”

print render('/images.html', context)

Page 24: Web весна 2012 лекция 4

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]

}

Page 25: Web весна 2012 лекция 4

Задача № 2. Изменение

объекта1) Два режима работы: отображение

формы и обновление объекта

2) Разделение по методу HTTP (GET | POST). Кеширование запросов

3) Использование спец. параметра (action)

4) Отображение ошибок и результата действия

Page 26: Web весна 2012 лекция 4

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.cgiid=%s&res=updated' % form['id'])

catch BaseException, e:

redirect('/cgi-bin/object.cgi?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)

Page 27: Web весна 2012 лекция 4

<form method=”POST” action=”/cgi-bin/object.cgi”>

{% 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>

Page 28: Web весна 2012 лекция 4

Best Practice

1) Разделять методы GET – получение, POST – обновление данных

2) Сообщать об ошибках и успехе

3) Проверять данные пользователя

а) на сервере – безопасность программы

б) на клиенте – удобство пользователя

4) Выделять неправильно введеные поля

Page 29: Web весна 2012 лекция 4

Задача № 3. Wizard1) Statefull vs Stateless.

2) Как передать данные между страницами?

выбор товара → информация о клиенте

→ дата и место доставки → подтверждение

3) Варианты:

- через URL

- через скрытые поля

- через Cookie

- через сессии

Page 30: Web весна 2012 лекция 4

Скрытые поля

<!-- 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>

Page 31: Web весна 2012 лекция 4

Cookie

1) Установка

Set-Cookie: name=val; path=/; domain=domain.ru; expires=Tue, 20 Mar 2012 11:52:54 GMT

2) Возврат

Cookie: name=val;name2=val2;is_visited=2011-13-15

Сессии1) Ключ сессии – в cookie

2) Данные – на сервере (memcached, database, files)

Page 32: Web весна 2012 лекция 4

Cookie с помощью Python CGI1) Установка

import Cookie

cookie = Cookie.SimpleCookie()

cookie['name'] = 'val'

cookie['name']['path'] = '/path'

print cookie

2) Получение

import Cookie

cookie = Cookie.SimpleCookie()

cookie.load('a=b;c=d')

for name in cookie: print '%s => %s' % (name, cookie[name])

Page 33: Web весна 2012 лекция 4

Достоинства и недостатки

CGIПлюсы:

1) простая концепция “скриптов”

2) стандарт – есть поддержка на любом хостинге

3) последовательное исполнение

Минусы и способы решения:

1) смешение кода и HTML → шаблонизаторы

2) повторение логики → вынесение кода в библиотеки

3) pretty urls → RewriteEngine

4) производительность (fork, exec, parse, db.connect) → кеширование кода (FastCGI, mod_perl etc)

Page 34: Web весна 2012 лекция 4

Pretty URLs

URL: /profile/mail/my

Скрипт: /cgi-bin/profile.cgi?email=my@ mail.ru

location ~* ^/profile/\w+/\w+/?$ {

rewrite ^/profile/(\w+)/(\w+)/?

/cgi-bin/profile.cgi?email=$2@$1.ru break;

proxy_pass http://backend;

}

Page 35: Web весна 2012 лекция 4

КешированиеЧто такое кеширование ? Виды кешей:

1) HTTP cache - сокращает загрузку статики

2) proxy cache – кеш страницы целиком

(либо части, подключаемой через ssi)

3) buffer cache – кеширование данных в OS

4) memcached – распределенный кеш в памяти

5) генерация статических файлов

6) отложенное выполнение. crond.

Page 36: Web весна 2012 лекция 4

Домашняя работа

1) реализовать calc_paginator

2) написать cgi скрипт для проверки. Список объектов – числа Фибоначчи до 10000

1) реализовать функцию redirect

2) написать cgi скрипт для проверки.

Например аналог bit.ly со статическими настройками.