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/LeiHello, Lei!
  • /pingpong
  • /unknownPage not found

小结

这一篇我们学会了:

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

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