0Pricing
Clojure Functional Programming & JVM Backend Development · 课时

深入理解 Ring 中间件

学习 Ring 中间件如何包装处理器,为 Compojure Web 应用添加日志记录、参数解析和会话处理等横切行为。

深入理解 Ring 中间件 是 CoddyKit 上的免费 Clojure Functional Programming & JVM Backend Development 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Clojure Functional Programming & JVM Backend Development 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Clojure Functional Programming & JVM Backend Development 课程共包含 4 节课。

本课时的部分内容尚未翻译,以英文显示。

What Is Middleware?

In Ring, a handler is a function that takes a request map and returns a response map. Middleware is a higher-order function that takes a handler and returns a new handler.

This lets you wrap behavior around your core logic without modifying it.

(defn wrap-example [handler]
  (fn [request]
    (handler request)))

The Wrapping Pattern

Every middleware follows the same shape: receive a handler, return a function that takes a request. You can act before or after calling the inner handler.

  • Before: inspect or modify the request
  • After: inspect or modify the response
(defn wrap-logging [handler]
  (fn [request]
    (println "Incoming:" (:uri request))
    (let [response (handler request)]
      (println "Status:" (:status response))
      response)))

Applying Middleware

You apply middleware by calling it on your handler. The result is a new handler that you pass to the server.

(def app
  (-> handler
      wrap-logging))

The Threading Macro

The -> threading macro is the idiomatic way to stack middleware. Each layer wraps the one before it.

Order matters: the last middleware listed is the outermost layer that sees the request first.

(def app
  (-> routes
      wrap-params
      wrap-session
      wrap-logging))

Built-in Middleware

The ring-defaults library bundles common middleware so you do not write it by hand.

  • wrap-params parses query and form params
  • wrap-session manages sessions
  • wrap-keyword-params turns string keys into keywords
(require '[ring.middleware.defaults :refer [wrap-defaults site-defaults]])

(def app
  (wrap-defaults routes site-defaults))

Modifying the Request

To add data for downstream handlers, assoc a key onto the request before calling the inner handler.

(defn wrap-user [handler]
  (fn [request]
    (let [user (lookup-user (:session request))]
      (handler (assoc request :current-user user)))))

Modifying the Response

To set headers or transform output, work on the response after calling the inner handler.

(defn wrap-content-type [handler]
  (fn [request]
    (let [response (handler request)]
      (assoc-in response [:headers "Content-Type"] "text/html"))))

Conditional Middleware

Sometimes you only want middleware on certain routes. You can apply it selectively rather than globally.

(defroutes app
  (GET "/public" [] public-handler)
  (-> (GET "/admin" [] admin-handler)
      wrap-authentication))

Exception Handling Middleware

A common pattern is wrapping all handlers in a try/catch to return a clean 500 response instead of leaking stack traces.

(defn wrap-errors [handler]
  (fn [request]
    (try
      (handler request)
      (catch Exception e
        {:status 500 :body "Internal Server Error"}))))

Order of Execution

Think of middleware as an onion. The request travels inward through each layer to the handler, then the response travels outward back through them.

  • Outermost middleware runs first on request, last on response
  • Innermost runs last on request, first on response
; request:  wrap-logging -> wrap-session -> wrap-params -> handler
; response: handler -> wrap-params -> wrap-session -> wrap-logging

Composing Reusable Middleware

Because middleware are just functions, you can group them into a single composed function and reuse it across multiple apps.

(defn wrap-common [handler]
  (-> handler
      wrap-logging
      wrap-errors
      wrap-params))

Quick Check

Test your understanding of middleware ordering.

Recap

You learned that middleware are higher-order functions wrapping handlers to add cross-cutting behavior.

  • They can modify the request before, or the response after
  • The -> macro stacks them like an onion
  • Libraries like ring-defaults bundle common ones

Next you can combine custom middleware with Compojure routes for full-featured apps.

常见问题解答

「深入理解 Ring 中间件」课时是免费的吗?

是的 — 「深入理解 Ring 中间件」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Clojure Functional Programming & JVM Backend Development 课程的其余内容,请升级到 CoddyKit PRO。 Clojure Functional Programming & JVM Backend Development 课程共包含 4 节课。

「深入理解 Ring 中间件」这节课中我会学到什么?

学习 Ring 中间件如何包装处理器,为 Compojure Web 应用添加日志记录、参数解析和会话处理等横切行为。 你通过在浏览器中直接运行的动手代码来练习 Clojure Functional Programming & JVM Backend Development,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Clojure Functional Programming & JVM Backend Development 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Clojure Functional Programming & JVM Backend Development 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「深入理解 Ring 中间件」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Clojure Functional Programming & JVM Backend Development 课中编写并运行代码吗?

能。每节 Clojure Functional Programming & JVM Backend Development 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Ring 与 HTTP 基础入门
  2. 使用 Compojure 进行路由
  3. 处理请求与响应
  4. 深入理解 Ring 中间件
← 返回 Clojure Functional Programming & JVM Backend Development