我使用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以及在用户登录后在客户端中启动频道,并且没有任何改变会话保持为空的事实。
答案 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就建立起来了!叫做;所以,在会话准备好之前不应该调用它。