为什么Sente的ring-req有cookie而不是会话?

时间:2016-11-20 18:58:06

标签: session cookies clojure sente

我使用Sente库通过websockets进行通信。沟通已经开始,但会议似乎缺失了。我像这样设置Sente:

;; According to https://github.com/ptaoussanis/sente
(let [{:keys [ch-recv send-fn connected-uids
              ajax-post-fn ajax-get-or-ws-handshake-fn]}
      (sente/make-channel-socket! (get-sch-adapter) {})]

  (def ring-ajax-post ajax-post-fn)
  (def ring-ajax-get-or-ws-handshake ajax-get-or-ws-handshake-fn)
  (def ch-chsk ch-recv)                                     ; ChannelSocket's receive channel
  (def chsk-send! send-fn)                                  ; ChannelSocket's send API fn
  (def connected-uids connected-uids))                      ; Watchable, read-only atom

(defmulti handle-message
          "Multimethod to handle messages coming from the clients"
          :id)

(defmethod handle-message
  :default
  [{:as ev-msg :keys [event id ?data ring-req ?reply-fn send-fn]}]
  (let [session (:session ring-req)
        uid (:uid session)]
    (printf "Ring request: %s\n" ring-req)
    (printf "Session: %s\n" session)
    (printf "UID: %s\n" uid)
    (printf "Unhandled event: %s\n" event)
    (printf "Thread id: %s\n" (.getId (Thread/currentThread)))
    (flush)
    (when ?reply-fn
      (?reply-fn {:umatched-event-as-echoed-from-from-server event}))))

(defmethod handle-message :chsk/ws-ping [arg]
  (println "ping"))              ; Ignore pings

(mount/defstate ^{:on-reload :noop}
                socket-server
                :start (sente/start-server-chsk-router!
                         ch-chsk
                         (fn [arg]
                           (handle-message arg)
                           (println "\n"))
                         #_{:simple-auto-threading? true})
                :stop (socket-server))

当我从客户端发送一条经过身份验证的消息时,我得到了这个输出:

Ring request: {:identity nil, :cookies {"ring-session" {:value "8df3a322-313a-4f16-873c-9ea7275af723"}}, :remote-addr "0:0:0:0:0:0:0:1", :params {:client-id "7a2d8913-ad69-4c82-83ed-30ffb1e3c50a"}, :flash nil, :route-params {}, :headers {"origin" "file://", "host" "localhost:3000", "upgrade" "websocket", "user-agent" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) projectx/0.1.0 Chrome/52.0.2743.82 Electron/1.3.3 Safari/537.36", "cookie" "ring-session=8df3a322-313a-4f16-873c-9ea7275af723", "connection" "Upgrade", "pragma" "no-cache", "sec-websocket-key" "g9lEvc59vyaE6RLbM36iyQ==", "accept-language" "en-US", "sec-websocket-version" "13", "accept-encoding" "gzip, deflate", "sec-websocket-extensions" "permessage-deflate; client_max_window_bits", "cache-control" "no-cache"}, :async-channel #object[org.httpkit.server.AsyncChannel 0x8958245 "/0:0:0:0:0:0:0:1:3000<->/0:0:0:0:0:0:0:1:64374"], :server-port 3000, :content-length 0, :form-params {}, :compojure/route [:get "/web-socket"], :websocket? true, :session/key nil, :query-params {"client-id" "7a2d8913-ad69-4c82-83ed-30ffb1e3c50a"}, :content-type nil, :character-encoding "utf8", :uri "/web-socket", :server-name "localhost", :query-string "client-id=7a2d8913-ad69-4c82-83ed-30ffb1e3c50a", :body nil, :multipart-params {}, :scheme :http, :request-method :get, :session {}}
Session: {}
UID: null
Unhandled event: [:projectx.core/boo "boo!"]
Thread id: 38

处理程序非常简单,设置如下:

(def app-routes
  (routes
    (GET "/web-socket" req (socket/ring-ajax-get-or-ws-handshake req))
    (POST "/web-socket" req (socket/ring-ajax-post req))
    #'service-routes
    (route/not-found
      "page not found")))

(defn app [] (middleware/wrap-base #'app-routes))

middleware / wrap-base包含会话处理,它看起来像这样:

(defn wrap-identity [handler]
  (fn [request]
    (println (:cookies request))
    (if-let [current-user-id (get-in request [:session :identity])]
      (if-let [current-user (when current-user-id (db/get-user-by-id {:id current-user-id}))]
        (handler (assoc request :current-user current-user))
        (handler (-> request
                     (dissoc :identity)
                     (dissoc-in [:session :identity])))))
      (handler request))))

(defn wrap-auth [handler]
  (let [backend (session-backend)]
    (-> handler
        wrap-identity
        (wrap-authentication backend)
        (wrap-authorization backend))))

(defn wrap-base [handler]
  (-> ((:middleware defaults) handler)
      wrap-auth
      (wrap-defaults
        (-> site-defaults
            (assoc-in [:params :keywordize] true)           ; Needed by Sente: https://github.com/ptaoussanis/sente#on-the-server-clojure-side
            (assoc-in [:params :urlencoded] true)           ; Needed by Sente: https://github.com/ptaoussanis/sente#on-the-server-clojure-side      
            (assoc-in [:security :anti-forgery] false)
            (assoc-in [:session :store] (ttl-memory-store (* 60 30)))))))

这对AJAX请求工作得很好。我甚至尝试在会话中设置:uid以及在用户登录后在客户端中启动频道,并且没有任何改变会话保持为空的事实。

1 个答案:

答案 0 :(得分:1)

问题出在客户端。在用户登录该会话以显示在套接字中之后,必须建立连接。我正在关注代码示例,如下所示:

;; https://github.com/ptaoussanis/sente
(let [{:keys [chsk ch-recv send-fn state]}
      (sente/make-channel-socket! "/web-socket"
                                  {:host     conf/remote-host:port
                                   :protocol (str conf/remote-protocol ":")
                                   :type     :auto})]
  (def chsk chsk)
  (def ch-chsk ch-recv)                                     ; ChannelSocket's receive channel
  (def chsk-send! send-fn)                                  ; ChannelSocket's send API fn
  (def chsk-state state))                                   ; Watchable, read-only atom

(defonce router_ (atom nil))
(defn stop-router! [] (when-let [stop-f @router_] (stop-f)))
(defn start-router! []
  (stop-router!)
  (reset! router_
          (sente/start-client-chsk-router!
            ch-chsk (fn [{:keys [ch-recv send-fn state event id ?data] :as arg}]
                      (println "Event" event)))))
错误地认为调用start-router将建立通信,但是只要make-channel-socket就建立起来了!叫做;所以,在会话准备好之前不应该调用它。