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。