You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Reitit异步拦截器出现Unsupported Context on :enter错误求助

Reitit拦截器中使用core.async go宏报错的解决方法

问题场景

我正在开发一款基于Reitit的HTTP应用,使用拦截器实现业务逻辑。但在拦截器的enter函数中包裹go宏后,调用接口触发错误;移除go宏则代码正常运行。

问题代码

(ns ic.reitit-interceptor-multithreading)

(require '[reitit.ring :as ring])
(require '[reitit.http :as http])
(require '[reitit.interceptor.sieppari :as sieppari])
(require '[clojure.core.async :refer [go]])
(defn interceptor [number]
  {:enter (fn [ctx]
            (go
              (println "in enter interceptor" number (.getName (Thread/currentThread)))
              (update-in ctx [:request :number] (fnil + 0) number)))})

(def app
  (http/ring-handler
   (http/router
    ["/api"
     {:interceptors [(interceptor 1)]}

     ["/number"
        {:interceptors [(interceptor 10)]
         :get {:interceptors [(interceptor 100)]
               :handler (fn [req]
                          (println "in handler")
                          {:status 200
                           :body (select-keys req [:number])})}}]])

   ;; the default handler
   (ring/create-default-handler)

   ;; executor
   {:executor sieppari/executor}))

触发错误

在REPL执行以下代码:

(require '[ic.reitit-interceptor-multithreading :refer :all])
(app {:request-method :get, :uri "/api/number"})

错误信息:

Loading src/ic/reitit_interceptor_multithreading.clj... done
(app {:request-method :get, :uri "/api/number"})
Execution error (ExceptionInfo) at sieppari.core/-invalid-context-type! (core.cljc:34).
Unsupported Context on :enter - clojure.core.async.impl.channels.ManyToManyChannel@4abe39b8
in enter interceptor 1 async-dispatch-3

问题原因

Reitit默认使用的Sieppari拦截器执行器,仅支持返回同步上下文对象或特定异步类型(如Future、Manifold Deferred),但go宏返回的是core.async的Channel对象,Sieppari无法直接识别处理这种类型,因此抛出错误。

解决方案

根据需求选择以下两种方式:

方式1:转换core.async Channel为Sieppari支持的类型

如果必须使用core.async的异步逻辑,需要将Channel转为Sieppari兼容的异步类型,推荐使用Manifold库处理:

首先添加Manifold依赖到项目,然后修改拦截器:

(ns ic.reitit-interceptor-multithreading)

(require '[reitit.ring :as ring])
(require '[reitit.http :as http])
(require '[reitit.interceptor.sieppari :as sieppari])
(require '[clojure.core.async :refer [go]])
(require '[manifold.deferred :as d])

(defn interceptor [number]
  {:enter (fn [ctx]
            ;; 将core.async Channel转为Manifold Deferred
            (d/from-source
              (go
                (println "in enter interceptor" number (.getName (Thread/currentThread)))
                (update-in ctx [:request :number] (fnil + 0) number))))})

;; 其余代码保持不变...

如果不想引入Manifold,也可以用<!!阻塞获取Channel结果(不推荐高并发场景,会阻塞线程):

(defn interceptor [number]
  {:enter (fn [ctx]
            (let [async-result (go
                                 (println "in enter interceptor" number (.getName (Thread/currentThread)))
                                 (update-in ctx [:request :number] (fnil + 0) number))]
              ;; 阻塞获取异步结果
              (<!! async-result)))})

方式2:使用Sieppari原生支持的异步方式

如果不需要core.async的复杂异步流程,直接用future实现多线程逻辑,Sieppari可直接处理Future类型:

(defn interceptor [number]
  {:enter (fn [ctx]
            (future
              (println "in enter interceptor" number (.getName (Thread/currentThread)))
              (update-in ctx [:request :number] (fnil + 0) number)))})

内容的提问来源于stack exchange,提问作者user51

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 12:15:21