Redis存储Ring Session

ring-middleware拥有良好的可扩展性。ring默认使用内存存储session(基于atom实现),本文演示如何使用redis存储session。源码地址

实现

首先在project.clj中引入ring-core依赖,

:dependencies [[ring/ring-core "1.4.0"]]

定义我们的SessionStore

(ns cs.redis.session
  (:require
   [ring.middleware.session.store :refer [SessionStore]])
  (:import [java.util UUID]))

;; redis连接配置
(def rds-session-config (atom nil))

(defn config-rds-session!
  [rds-configs]
  (reset! rds-session-config rds-configs))

(defmacro wcar* [& body]
  `(car/wcar (:server @rds-session-config) ~@body))

;; 实现存、取、删方法
(defn store-code
  "Store a `key`-`val` pair. If `val` is nil, a random string
  will be generated. If `ttl`(secs) is nil, the code will not expire.

  Returns the val stored."
  [{:keys [key val ttl]}]
  {:pre [key val]}
  (wcar*
   (car/multi)
   (car/set key val)
   (when ttl (car/expire key ttl))
   (car/exec))
  val)

(defn get-code
  [{:keys [key]}]
  {:pre [key]}
  (wcar* (car/get key)))

(defn remove-code
  [{:keys [key]}]
  {:pre [key]}
  (wcar* (car/del key)))

(defn touch
  "Touch a key to reset the access time.
  Returns nil if the key is already expired, otherwise returns the value of the key."
  [{:keys [key ttl]}]
  {:pre [key ttl]}
  (first
   (let [key key]
     (wcar*
      (when (car/get key)
        (car/expire key ttl))))))


;; 定义RedisSessionStore
(defn- make-session-key [key]
  (str (or (:session-prefix @rds-session-config) (subs (str (UUID/randomUUID)) 25)) key))

(deftype RedisSessionStore []
  SessionStore
  (read-session [_ key]
    (touch {:key (make-session-key key) :ttl (or (:session-ttl @rds-session-config) 7200)}))
  (write-session [_ key data]
    (let [key (or key (str (UUID/randomUUID)))]
      (store-code {:key (make-session-key key) :val data :ttl (or (:session-ttl @rds-session-config) 7200)})
      key))
  (delete-session [_ key]
    (remove-code {:key (make-session-key key)})
    nil))

(defn redis-session-store
  "Redis session store. Redis db and session key prefix are configured
  in edn files."
  []
  (RedisSessionStore.))

如何使用

  1. Web应用启动时配置redis:
    (cs.redis.session/config-rds-session! {:server rds-server-ip ;; redis服务器ip
                          :session-ttl session-ttl-in-secs ;; session超时时间(秒)
                          :session-prefix session-key-prefix ;; session-key的前辍;默认为随机字符串
                          })
    
  2. 配置ring-middleware
    ;; compojure方式
    (-> (compojure.core/routes your-routes)
        ;;(wrap-other-middlewares)
        (ring.middleware.defaults/wrap-defaults (assoc-in site-defaults [:session :store] (redis-session-store))))
    ;; 或如果用lib-noir时
    (noir.util.middleware/app-handler
     [your-routes]
     :ring-defaults (assoc-in site-defaults [:session :store] (redis-session-store)))
    

参考

Ring Sessions

Comment