Знакомство с Presto — Часть Четвёртая

в 6:27, , рубрики: framework, ruby, Веб-разработка, метки: ,

В данной части приведён список методов для работы с HTTP Api.

Список HTTP Api опций приведён в первой части данного туториала.
Список дополнительных HTTP Api опций приведён в третей части.


Оглавление


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

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js