Clojure Web 开发从零开始(三):路由与中间件

前两篇文章中,我们已经完成了一个最简单的 HTTP 服务器,返回固定的 "Hello HTTP!"。
但一个真正的 Web 应用需要处理不同的路径 (routes) 和请求逻辑。
这一篇,我们将引入 Compojure 来实现路由,并学习如何使用 Ring 中间件。


1. 添加 Compojure 依赖

在 project.clj 中新增 Compojure:

[compojure "1.6.1"]

更新后的 project.clj:

(defproject clj-httpbin "0.1.0"
  :description "Clojure httpbin clone"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :main clj-httpbin.core
  :dependencies [[org.clojure/clojure "1.10.1"]
                 [http-kit "2.3.0"]
                 [compojure "1.6.1"]])

执行:

lein deps

2. 定义路由

在 src/clj_httpbin/core.clj 中:

(ns clj-httpbin.core
  (:require [org.httpkit.server :as http]
            [compojure.core :refer :all]
            [compojure.route :as route])
  (:gen-class))

(defroutes app
  (GET "/" [] "<h1>Hello, World!</h1>")
  (GET "/hello/:name" [name] (str "<h1>Hello, " name "!</h1>"))
  (GET "/ping" [] "pong")
  (route/not-found "Page not found"))

(defn -main []
  (println "Starting server on port 8080 ...")
  (http/run-server app {:port 8080}))

3. 使用 Ring 中间件

Ring 中间件是对 app 的包装,用于统一处理请求或响应,例如日志、JSON 解析、跨域设置等。

添加 ring-defaults:

[ring/ring-defaults "0.3.2"]

并修改 core.clj:

(ns clj-httpbin.core
  (:require [org.httpkit.server :as http]
            [compojure.core :refer :all]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]])
  (:gen-class))

(defroutes routes
  (GET "/" [] "<h1>Hello, World!</h1>")
  (GET "/hello/:name" [name] (str "<h1>Hello, " name "!</h1>"))
  (GET "/ping" [] "pong")
  (route/not-found "Page not found"))

(def app
  ;; 使用 site-defaults 包裹路由,自动启用常见中间件
  (wrap-defaults routes site-defaults))

(defn -main []
  (println "Starting server on port 8080 ...")
  (http/run-server app {:port 8080}))

4. 测试路由与中间件

启动:

lein run

测试不同路径:

curl http://localhost:8080/
curl http://localhost:8080/hello/Lei
curl http://localhost:8080/ping
curl http://localhost:8080/unknown

输出结果:

  • / → Hello, World!
  • /hello/Lei → Hello, Lei!
  • /ping → pong
  • /unknown → Page not found

小结

这一篇我们学会了:

  • 使用 Compojure 定义路由
  • 使用 Ring 中间件 提供默认功能

下一篇将继续扩展,增加 返回 JSON 和 处理表单提交 的能力,让应用更接近真实的 Web API。