1

我正在使用 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 以及在用户登录在客户端中启动通道,但没有改变会话保持为空的事实。

4

1 回答 1

2

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

;; 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 时立即建立的!叫做; 因此,在会话准备好之前不应调用它。

于 2016-11-20T20:07:41.797 回答