在上一個章節,咱們已經構建了一個簡單的應用程序。這讓咱們體驗到了溫馨的開發環境以及提供給了咱們一個快速領略項目結構的機會。可是如今咱們須要慢下腳步來花些時間來理解一下組件運行的細節。html
因爲Clojure社區崇尚的是簡單、靈活的價值觀,因此事情的解決每每會沒有一個固定的解決規範。在Web堆棧這一塊,幾乎全部的組件都會有它的替代品。你能夠挑選一個最適合你的來開發應用。在這本書中,咱們將着重於 Ring/Compojure 來進行構建真實可用的應用。web
在上一章節已經介紹了一個簡單的應用:支持用戶留言,而且能夠查看到全部用戶的留言。咱們圍繞着項目目錄中的文件,來分析了他們各自所要達成的目的。然而,咱們並無很是仔細的去分析文件中的代碼是什麼。而在本章中,你將學習一些必要的背景知識,以致於充分理解咱們的第一個應用。服務器
因爲Clojure Web 堆棧是創建在JAVA HTTP Servlet API的基礎上的,應用程序能夠部署在任何的Servlet容器之上,好比Jetty、GlassFish或者是Tomcat。cookie
Clojure 的應用程序能夠獨立進行運行,也能夠和已經存在的JAVA 應用部署在一個服務器上。(Clojure applications can be run standalone or can be deployed side-by-side with existing Java applications using an application server. 這句求更好的說法~我以爲翻譯可能有誤差。)session
還因爲不少的雲服務器運行的是JAVA虛擬機,你也能夠將你的應用部署到像 Amazon Web Services, Google App Engine, Heroku 以及 Jelastic 這樣的平臺上面。閉包
一個 servlet 接收到一個請求而後生成一個符合HTTP協議的相應的反饋。
這個API實現了一系列web應用須要的核心的方法:諸如cookies,sessions,還有像URL 重寫這樣的功能。然而,servlets是一個專門爲JAVA進行設計的,而直接在Clojure下使用並無提供最好的體驗。app
也不像其它的許多平臺——好比Rails或者是Django這些,Clojure並無一個總體的框架。與此相對的,你能夠一塊兒使用好幾個庫來構建一個應用,咱們將集中介紹幾個經常使用的進行web開發的庫。框架
Ring的目標是將HTTP的細節進行抽象,以成爲一個簡單的模塊化的API,用於構建大規模的應用。若是你使用Ruby或者Python進行web開發,那麼它對應的就應該像是WSGI或者Rack這樣的庫。ide
因爲Ring已經成爲了構建Web應用的事實上的標準,圍繞着它已經開發出了不少的工具和中間鍵。雖然在大多數狀況下你並不會去直接使用Ring,但它會提高你對於設計的理解,也能幫助你更好的排查出本身應用中的故障。模塊化
Ring包含了四個基礎的組件:處理器、請求、應答以及中間件(the handler, the request, the response, and the middleware),讓咱們一個部分一部分的看過來。
Ring使用了Clojure Map來表示客戶端的請求以及服務器端返回的相應內容。控制器的功用就是處理進入的請求。它接收一個請求Map而後返回一個響應Map。一個簡單的Ring控制器能夠是這個樣子的:
(def handler [request-map] {:status 200 :headers {"Content-Type" "text/html"} :body (str "<html><body> your IP is: " (:remote-addr request-map) "</body></html>")})
你能夠清楚的看到,這裏接收了一個至關於HTTP請求的請求Map,而後返回了一個至關於HTTP響應的Map。而後Ring就會使用這個Map去生成一個HTTP Servlet的請求以及相應的對象。(Ring then takes care of generating an HTTP servlet request, and response objects from these maps.)
前面的處理程序主要的功能就是返回一個HTML字符串——其中帶有IP地址,而且設置相應狀態爲200。做爲一個常見的操做,Ring專門提供了一個API來輔助生成這樣的應答:
(defn handler [request-map] (response (str "<html><body> your IP is: " (:remote-addr request-map) "</body></html>")))
若是你想要建立一個自定義的響應,你只須要寫一個能夠接收請求Map,而且返回一個你自定義的響應的函數就能夠了。接下來讓咱們看看請求和響應的Map格式是什麼樣的。
請求響應的Map通常都包含服務器端口、URI、服務器地址和內容類型,還要加上主體部分(body)。在這個Map中出現的關鍵詞都是和servlet API 以及 官方 HTTP RFC 進行對應的。
請求定義了下面的一些鍵。要注意的是下面像 :ssl-client-cert
這樣的鍵並非每一個請求都必要的。
:http
或者 :https
:get
:head
:options
:put
:post
:delete
:context
可用的時候,會添加到它前面。除了這些Ring已經定義了的鍵以外,還可使用中間件函數來擴展請求Map來添加一些特殊的鍵值。在這個章節的後面咱們會演示怎麼去作。
在響應的Map中只包含了3個鍵值用來描述HTTP響應:
狀態碼是一個數字,它在HTTP RFC中有定義,最小的有效數值是100。
頭是一個包括了HTTP頭鍵值對的Map。頭能夠是字符串也能夠是一組字符串組成,在這種狀況下,一個鍵對應其中的一個字符串。
最後,響應的主體部分是一個字符串,它會原樣返回到客戶端上。若是它是一個序列,那麼它就會將每個元素的字符串發送到客戶端。若是該響應是一個文件或者是輸入流,那麼服務器會將內容發送到客戶端。
中間件容許將控制器(the handlers)包在函數中,以這樣的方式來修改處理的請求。中間件還常常用來擴展基礎的Ring控制器來適應你本身的應用。
中間件處理程序是一個接受已經存在的處理程序以及一些可選參數,返回一個新的添加了一些行爲的處理程序。下面有一個例子:
(defn handler [request] (response (str "<html><body> your IP is: " (:remote-addr request) "</body></html>"))) (defn wrap-nocache [handler] (fn [request] (let [response (handler request)] (assoc-in response [:headers "Pragma"] "no-cache")))) (def app (wrap-nocache handler))
在這個例子中,封裝函數接收一個處理函數,而且返回一個新的處理程序來做爲處理程序。因爲返回的函數定義在當前的包裝函數之中,它能夠直接在裏面引用處理函數。當使用的時候,它將處理請求而且在響應Map中添加Pragma: no-cache
。
該包裝函數被稱之爲「閉包」,由於它包裝了操做函數以及參數,而且容許直接使用返回的函數。
剛剛使用的技術可讓咱們建立出一些簡單的方法,每個均可以解決一個特定的問題。咱們能夠將他們方便的連接起來來實現複雜的邏輯。
適配器處於底層的HTTP協議以及處理程序之間,他們提供着必要的配置,諸如端口映射,以及處理HTTP請求的解析成爲請求Map,將響應Map構建成爲HTTP的響應。你一般不須要直接經過適配器進行交互。咱們不會再繼續展開了。
年後第一個星期事情就是滿滿的啊!簡直出乎意料,昨天休息了一天~只有今天有時間來繼續完成沒有完成的坑了~
翻譯的可能仍是一如既往的爛,可是我會找機會從新潤色一下的。 相信本身並不會放棄,繼續持續的更新下去的。