服务器在基座中发送事件返回空响应

问题描述 投票:0回答:1

我目前正在使用 Clojure、Pedestal 和 Jetty 在 Web 应用程序中实现服务器发送事件 (SSE)。

当我在后端打印消息时,通道已打开,当我调用

io.pedestal.http.sse/send-event
时,它返回 true,但是在前端,我在浏览器控制台中的 Javascript 中没有看到 console.log() 打印。就好像没有收到数据一样。我在Postman中测试了SSE连接,它是成功的,但响应是
(empty)

后端:

    (def SSE-REGISTRY (atom {}))
     
     (defn get-user-channel [token]    
       (get @SSE-REGISTRY token))
     
     (defn test-print [channel]    
       (println "channel:" channel) ;; channel:#object[clojure.core.async.impl.chan...]   
       (println "channel opened:" (not (chan/closed? channel))) ;; channel opened: true  
       (println "sent-event:" 
       (sse/send-event channel "status"
         (json/write-str {:id 1
                          :workflowId 3
                          :status :GOOD}) ;; sent-event: true
     
     (defn send-sse-msg [name data id]   
       (when-let [sse-channels (vals @SSE-REGISTRY)]
         (doseq [channel sse-channels] 
           (when-not (chan/closed? channel)
             (test-print channel)
             (sse/send-event channel name data id)))))   

(def sse-route ["/rest/sse" :get 
                  (sse/start-event-stream send-sse-msg 60 100) 
                  :route-name :sse])
     
     (defn create-sse-channel []   
        (async/chan (async/sliding-buffer 100)))

前端:

 const protocol = window.location.protocol;
const host = window.location.port; 
const sseUrl = protocol + '//'+ host + '/rest/sse';
const RUN_BUTTON_STATUS_TIME = 2000;
const sseInitOptionsMap = {
                            headers: {
                                       'Content-Type': 'text/event-stream; charset=utf-8',
                                       'Connection': 'keep-alive', 
                                       'Cache-Control': 'no-cache' 
                                      },
                            withCredentials: true,
                            https: {rejectUnauthorized: true}
                          };

export const eventSource = new EventSource(sseUrl, sseInitOptionsMap);
eventSource.addEventListener('integrationStatus', sendStatusHandler);
eventSource.addEventListener('stopAction', sendStopActionHandler);

eventSource.onopen = (e) => {
  console.log("SSE connection opened:" + e);
};

eventSource.onerror = (e) => {
  console.log("error:" + e);
  if (e.readyState == EventSource.CLOSED) {
      console.log("connection closed:" + e);
  } else {
    eventSource.close();
    console.log("SSE connection closed:" + e);
  }
};

export function sendStatusHandler(event) {
  const data = JSON.parse(event.data);
  console.log("data:" + data);
  let id = data.id;
  let workflowId = data.workflowId;
  let status = data.status;
  cljsDisp("set-global-operation-status", id, workflowId, status);
  configurtorActionRunButtonStatus(id, workflowId, status);
  setTimeout(cljsDisp("get-last-run-action-data", id, workflowId, status),
             300);
}

function configurtorActionRunButtonStatus (id, workflowId, status) {
  if (status === "GOOD") {
    showStatus(id, workflowId, true);
  } else if (status === "BAD") {
    showStatus(id, workflowId, true);
    cljsDisp("configurator-error-message-show", id, workflowId, true);
  } else {
    cljsDisp("configurator-action-run-button-status-visible?", id, workflowId, false);
  }
}

export function sendStopWorkflowHandler(event) {
  const data = JSON.parse(event.data);
  console.log("data:" + data); // prints nothing
  let workflowId = data.workflowId;
  cljsDisp("stop-action-by-sse-msg", workflowId);
}

function showStatus(integrationId, operationId, showStatus) {
  setTimeout(cljsDisp("configurator-action-run-button-status-visible?", 
                      integrationId, operationId, showStatus),
             RUN_BUTTON_STATUS_TIME);
}

export function closeSse() {
  if (eventSource.readyState != eventSource.CLOSED) {
    eventSource.close();
  }
}

我好像错过了什么。你能帮我吗。问题在于,Clojure 与 SSE 的 Pedestal 实现的例子并不多。大多数都是 JavaScript 和其他语言。 这是基座SSE本身的实现

javascript clojure response server-sent-events pedestal
1个回答
0
投票

基座文档上有一个小示例,您可以将其添加为单独的路线。

您的代码的基本问题是,当您使用以下命令创建拦截器时:

(sse/start-event-stream send-sse-msg 60 100) 

send-sse-msg 函数应该是一个带有 2 个参数的函数,即原始请求的通道和上下文。上下文可以像任何其他拦截器一样被解构。

使用上下文的文档示例的稍微修改版本是:

(defn sse-stream-ready
  "Starts sending counter events to client."
  [event-ch context]
  (let [count-num (Integer/parseInt
                   (get-in context [:request :query-params :counter] "5"))]
    (loop [counter count-num]
      (async/put!
       event-ch {:name "count"
                 :data (str counter ", T: "
                            (.getId (Thread/currentThread)))})
      (Thread/sleep 2000)
      (if (> counter 1)
        (recur (dec counter))
        (do
          (async/put! event-ch {:name "close" :data "I am done!"})
          (async/close! event-ch))))))

您的代码看起来更像是您将事件通道保存到注册表中(由某个上下文元素键入?),并让另一个异步函数向所有通道发送消息(我在那里推断类似聊天)。

© www.soinside.com 2019 - 2024. All rights reserved.