Продолжая тему web-разработки на Clojure, расскажу об использовании сессий в Ring. С наскоку разобраться в этой теме чуть сложнее, чем с той же маршрутизацией, поэтому рассмотрим реализацию сессий в подробностях.
Вначале, разберемся, что такое request и response в Ring. Вообще, request и response – это обычный map, который Ring возвращает в пользовательскую функцию. В этом легко убедиться, добавив в маршруты (здесь я использую Compojure):
(defroutes main-routes . . . (GET "/request" request (str request)) . . .)
Теперь если набрать в нашем веб-приложении адрес /request, то в броузере будет примерно следующее:
{:remote-addr "127.0.0.1", :scheme :http, :query-params {}, :session {},
:form-params {}, :multipart-params {}, :request-method :get, :query-string nil,
:route-params {}, :content-type nil, :cookies {"ring-session" {:value
"7d2c9094-b6d0-4dd3-8f0d-5457cb675fbf"}}, :uri "/request",
:server-name "127.0.0.1", :params {}, :headers {"user-agent" "Mozilla/5.0 (X11;
Linux i686; rv:2.0) Gecko/20100101 Firefox/4.0", "cookie"
"ring-session=7d2c9094-b6d0-4dd3-8f0d-5457cb675fbf", "keep-alive" "115",
"accept-charset" "ISO-8859-1,utf-8;q=0.7,*;q=0.7", "accept"
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", "host"
"127.0.0.1:3000", "cache-control" "no-cache", "accept-encoding" "gzip, deflate",
"pragma" "no-cache", "accept-language" "en-us,en;q=0.5", "connection" "keep-alive"},
:content-length nil, :server-port 3000, :character-encoding nil,
:body #<Input org.mortbay.jetty.HttpParser$Input@1590164>}
В ключе :session как раз и хранится сессия. Полученную через метод GET сессию можно прочитать, а отправленную в response – записать.
Добавим следующие маршруты:
(defroutes main-routes . . . (GET "/test-get" {params :params, session :session} (my-test-get params session)) (POST "/test-post" {params :params, session :session} (my-test-post params session)) . . .)
И реализуем функции:
(defn with-session [session response] (merge response {:session (merge (response :session) session)})) (defn my-test-get [params session] (str "<html><body>" (:my session) "<form action=\"/test-post\" method=\"post\"> <input type=\"submit\" value=\"Submit\" /> </form> </body></html>")) (defn my-test-post [params session] (let [old (session :my) new (str old "@")] (with-session {:my new} (redirect-to "/test-get"))))
Функция my-test-get выводит html-страницу с ключем :my из сессии и пустой формой с кнопкой Submit. Эта кнопка инициирует POST-запрос на адрес /test-post, в результате которого после маршрутизации будет вызвана функция my-test-post. Она, в свою очередь, добавит к существующей сессии в ключ :my дополнительный символ '@' и выполнит редирект на адрес /test-get. Функция with-session заменит старую сессию на новую с новым значением ключа :my.
Остается только добавить, чтобы это работало, необходимо заюзать ring.middleware.session, и изменить функцию app:
(def app (-> (handler/site main-routes) wrap-session))
Функцию with-session позаимствовал у Михаила Филоненко из его статьи о сессии в Ring.
Комментариев нет:
Отправить комментарий