В данной части приведён список методов для работы с HTTP Api.
Список HTTP Api опций приведён в первой части данного туториала.
Список дополнительных HTTP Api опций приведён в третей части.
- http.params, http.get_params, http.post_params — HTTP параметры
- http.route — alias http.r — URL конструктор
- http.pass — передаём контроль другому action-у или controller-у
- http.halt — завершаем выполнение любого кода и возвращаем ответ браузеру
- http.redirect, http.delayed_redirect — перенаправляем браузер по другому адресу
- http.reload — обновляем страницу
- http.cookies — работаем с куками
- http.session — работаем с сессиями
- http.session.confine / http.cookies.confine — делаем сессии/куки только читаемыми(readonly)
- http.confine — ограничиваем доступ и возможности
- http.sandbox — локально ограничиваем доступ и возможности
- http.user, http.reset_auth — состояние и отмена авторизации
- http.get/http.xhr_get, http.post/http.xhr_post — встроенный браузер
- http.env — детали текущего окружения
- http['Some-Header'] — читаем/устанавливаем HTTP header-ы
- http.action — текущий action
- Утилиты
http.params, http.get_params, http.post_params
— HTTP параметры
http.params
— содержит микс из GET и POST параметров.
http.get_params
или http.GET
— GET параметры.
http.post_params
или http.POST
— POST параметры.
Важно: Имена параметров являются строками, а не символами.
/some/path/?var=val
puts http.params['var']
#> val
Все параметры доступны только для чтения и только на уровне controller instance-а.
оглавление↑
http.route — alias http.r
— URL конструктор
Формирует URL в контексте заданного controller-а. Принимает любое количество аргументов.
Финальный URL будет состоять из корневого адреса controller-а и пути сконструированного из переданных аргументов.
class Index
http.map
end
Index.http.route 'some', 'path'
#=> /some/path
class News
http.map :news
end
News.http.route 'some', 'path'
#=> /news/some/path
Если первый аргумент является symbol-ом и controller содержит action с таким именем,
финальный URL будет состоять из адреса action-а и пути сконструированного из переданных аргументов.
class Index
http.map
def index
http.route :edit, :some, :args
#=> /edit/some/args
end
def edit
end
end
class News
http.map :news
def index
http.route :latest___items, :rss
#=> /news/latest-items/rss
end
def latest___items content_type
end
end
News.http.route 'some', 'path'
#=> /news/some/path
Если передать хэш, он будет превращён в HTTP параметры
http.route :action, :var => 'val'
#=> /action?var=val
Поддерживаются конечно и вложенные параметры.
http.r :edit, :var => ['1', '2', '3']
#=> /edit?var[]=1&var[]=2&var[]=3
http.r :edit, :vars => {:var1 => '1', :var2 => '2'}
#=> /edit?vars[var1]=1&vars[var2]=2
оглавление↑
http.pass
— передаём контроль другому action-у или controller-у
При передаче контроля, передаются также все данные, так что можно передавать целые POST формы не переживая за потерю данных.
def index type, id
http.pass :render if http.params['render']
end
private
def render type, id
end
/news/100 => /render/news/100
Можно также передать любые аргументы методу получателю
http.before do
if match = http.path.match(%r{^/(d+)/([a-z]+)/([a-z]+)$})
http.pass match[2], match[1], match[3]
end
end
def news id, action
end
/100/news/delete => /news/100/delete
Если последний аргумент является controller-ом, контроль будет передан ему
class News
include Presto::Api
http.map :news
def index id, page = 1
end
end
class Catchall
include Presto::Api
http.map
def index id, action
http.pass :index, News if http.params['type'] == 'news'
end
end
/100 => /news/100
/100/2 => /news/100/2
Если назначить блок, он будет выполнен непосредственно перед передачей контроля
def index type, id
http.pass :render do
puts 'leaving #index... flying to #render...'
end
end
оглавление↑
http.halt
— завершаем выполнение любого кода и возвращаем ответ браузеру
возвращаем пустой ответ
def index
http.halt if http.params['return-empty-body']
end
возвращаем осмысленный ответ
def index
http.halt 'Hit the Road Jack' if malicious_params?
end
возвращаем ошибку и соответвующий статус код
def index
begin
# some logic
rescue => e
http.halt exception_to_human_error(e), status: 500
end
end
если последний аргумент является хэшом, все значения(кроме :status) добавляются к header-ам
def news
if http.params['return-rss']
http.halt rssify(@items), 'Content-Type' => http.mime_type('.rss')
end
end
если первый аргумент является array-ем, он интерпретируется как Rack Response
def download
http.halt [200, {'Content-Disposition' => "attachment; filename=some-file"}, some_IO_instance]
end
оглавление↑
http.redirect, http.delayed_redirect
— перенаправляем браузер по другому адресу
http.redirect приостановит выполнение любого кода и перенаправит браузер по новому адресу.
http.delayed_redirect перенаправит браузер только после выполнения кода текущего action-а или callback-а.
обычный редирект
http.redirect '/some/path'
используем URL конструктор вместо статического адреса
class News
include Presto::Api
http.map :news
def read id
end
end
class Articles
include Presto::Api
http.map :articles
def index
http.redirect http.route # => /articles
http.redirect http.route(:read, 100) # => /articles/read/100
http.redirect News.http.route # => /news
http.redirect News.http.route(:read, 100) # => /news/read/100
end
def read id
end
end
по умолчанию используется статус код 302, но можно изменить его передав в качестве второго аргумента
http.redirect http.route(:logout), 301
оглавление↑
http.reload
— обновляем страницу
обновляем страницу с текущими GET параметрами
http.reload
обновляем страницу с модифицированными GET параметрами
http.reload :some => 'param', :some_another => :param
оглавление↑
http.cookies
— работаем с куками
читаем куки
http.cookies['cookie-name']
устанавливаем куки
http.cookies['cookie-name'] = 'value'
можно также установить куки с разными опциями, задав значение в виде хэша
http.cookies['question_of_the_day'] = {:value => 'who is not who?', :expires => Date.today + 1, :secure => true}
удаляем куки
http.cookies.delete 'cookie-name'
оглавление↑
http.session
— работаем с сессиями
читаем сессии
http.session['session-name']
устанавливаем сессии
http.session['session-name'] = 'value'
удаляем сессии
http.session.delete 'session-name'
Хранилище
По умолчанию сессии хранятся в оперативной памяти.
Это можно легко исправить посредством Presto.http.session_pool
mongodb = Mongo::Connection.new('localhost').db('app-sessions')
Presto.http.session_pool Presto::Cache::MongoDB.new(mongodb)
ttl — удаляем неактивные сессии возраст которых превышает ttl
ttl задаётся в секундах.
Значение по умолчанию — 86_400, то есть неактивные сессии будут жить ровно сутки.
Увеличить/уменьшить данное значение можно через Presto.http.session_ttl
Presto.http.session_ttl 3600
Теперь неактивные сессии будут жить только час.
оглавление↑
http.session.confine / http.cookies.confine
— делаем сессии/куки только читаемыми(readonly)
Используете http.cookies.confine
/http.session.confine
в случаях когда определённый slice, controller или action должны иметь readonly доступ к кукам/сессиям.
Устанавливаем readonly bit на уровне slice-а или controller-а
http.before do
http.cookies.confine
http.session.confine
end
Устанавливаем на уровне action-а, через callback
http.before :action_name do
http.cookies.confine
http.session.confine
end
Устанавливаем на уровне action-а, прямо внутри самого action-а
def :action_name
http.cookies.confine
http.session.confine
# some logic
end
оглавление↑
http.confine
— ограничиваем доступ и возможности
Борьба с ветровыми мельницами продолжается…
Иногда нужно чтобы определённые controller-ы или slice-ы работали в readonly режиме.
Под readonly имеется в виду:
- нельзя читать/устанавливать сессии/куки/header-ы
- нельзя читать/модифицировать env
- нельзя сделать halt, pass, redirect
Всё это можно запретить разом или выборочно, для всех action-ов или только для некоторых.
Ограничиваем все action-ы по всем возможностям
http.before do
http.confine
end
Можно конечно ограничить возможности выборочно.
Для этого, разрешаемые возможности передаются как аргументы.
В примере ниже мы ограничим все action-ы по всем возможностям кроме редиректа.
http.before do
http.confine :redirect
end
Ограничиваем только action #render, дав ему права читать/устанавливать header-ы а также возможность делать #halt
http.before :render do
http.confine :[], :[]=, :halt
end
оглавление↑
http.sandbox
— локально ограничиваем доступ и возможности
Иногда нужно ограничивать доступ не для целого action-а а лищь для одного рендера внутри action-а.
Для этого используется http.sandbox
Логика идентична http.confine
— без аргументов блокируются все возможности,
с аргументами разрешаются только переданные возможности.
рендерим шаблон с изменённым контекстом, в котором место обычного http api занимает api ограниченный по всем параметрам
def latest_news
# some logic
banners = view.render_view 'untrusted-templates/banners', http: http.sandbox
end
рендерим шаблон с изменённым контекстом, в котором место обычного http api занимает api умеющий лишь читать сессии и куки
def latest_news
# some logic
sandbox = http.sandbox(:session, :cookies)
banners = view.render_view 'untrusted-templates/banners', http: sandbox
end
оглавление↑
http.user, http.reset_auth
— состояние и отмена авторизации
Если авторизация прошла успешно, авторизированный пользователь будет доступен через http.user
Если же авторизация не прошла или не запрашивалась — http.user
всегда nil.
http.reset_auth позволяет отменить текущую авторизацию.
Работает ресет только для HTML Auth.
оглавление↑
http.get/http.xhr_get, http.post/http.xhr_post
— встроенный браузер
Позволяет обращаться к разным частям приложения через HTTP запрос.
По своему существу, сделанный HTTP запрос близок к идентичности с реальным HTTP запросом, сделанный через браузер.
Очень удобный инструмент как в тестировании так и в производстве.
Первый аргумент это всегда имя существующего action-а, соответственно всегда в виде символа.
Остальные аргументы будут превращены в HTTP представление и переданы запрашиваемому action-у.
#xhr_get b #xhr_post делают тоже самое что #get и #post, только имитируя Ajax запрос.
запрашиваем баннер из другого controller-а
class Forum
include Presto::Api
http.map :forum
def banner layout = 'horizontal'
@layout = layout
view.render_partial
end
end
class News
include Presto::Api
http.map :news
def hot
# some logic
@banner = Forum.http.get :banner, 'vertical'
end
end
создаём форум аккаунт для пользователей которые только что создали блог аккаунт
class Forum
include Presto::Api
http.map :forum
def register
# some logic
end
end
class Blog
include Presto::Api
http.map :blog
def register
# some logic
Forum.http.post :register, http.post_params
end
end
оглавление↑
http.env
— детали текущего окружения
puts http.env['SERVER_SOFTWARE']
#> thin 1.3.1 codename Triple Espresso
puts http.env['HTTP_CONNECTION']
#> keep-alive
и многое другое
оглавление↑
http['Some-Header']
— читаем/устанавливаем HTTP header-ы
Данный метод позволяет читать/устанавливать header-ы которые следует передать браузеру.
puts http['Max-Forwards']
#=> nil
http['Max-Forwards'] = 5
puts http['Max-Forwards']
#=> 5
Браузеру будет передан header Max-Forwards=5
оглавление↑
http.action
— текущий action
Удобен для callback-ов и при установки разных опций.
http.before do
if http.action == :order
# do some pre-order preparations
end
end
http.content_type :rss, :xml do
case http.action
when :rss
# do some stuff
when :xml
# do another stuff
end
end
оглавление↑
Утилиты
Включенны все методы из Rack::Utils и Rack::Request.
А также следующие методы из CGI:
- escape_html
- unescape_html
- escape_element
- unescape_element
- rfc1123_date
- pretty
Естественно все они доступны через http api:
http.escape_path
http.escape_html
http.path_info
# etc
Другие утилиты
http.mime_type — возвращает mime_type соответствующий переданному расширению
http.mime_type '.html' #=> "text/html"
http.mime_type '.css' #=> "text/css"
http.mime_type '.js' #=> "text/js"
http.mime_type '.txt' #=> "text/plain"
Автор: slivu