版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
輕量級Web應用開發(fā)目錄\h第1章環(huán)境配置與工具準備\h1.1Shell\hzsh的一些好用的特性\h1.2管道\h1.3幾個常用命令\h1.3.1文件查找命令find\h1.3.2網(wǎng)絡命令curl\h1.3.3文件搜索grep\h1.3.4定時任務crontab\h1.3.5JSON查詢利器jq\h1.4編輯器\h1.4.1Vim編輯器\h1.4.2SublimeText編輯器\h1.5程序啟動器\h1.5.1Launchy\h1.5.2Alfred\h1.6關于Windows\h第2章Web應用服務器\h2.1Rack\h2.1.1rackup\h2.1.2Rack中間件\h2.2Sinatra\h2.2.1404頁面\h2.2.2使用模板引擎\h2.2.3簡單認證中間件\h2.3Grape\h一個實例\h第3章數(shù)據(jù)庫訪問層\h3.1數(shù)據(jù)庫的訪問\h3.2數(shù)據(jù)庫方案(schema)的修改\h3.3ActiveRecord\h3.3.1和Rails一起使用\h表關聯(lián)\h3.3.2獨立使用(在既有數(shù)據(jù)庫中)\h查找記錄\h3.3.3校驗\h3.4DataMapper\h使用DateMapper\h第4章客戶端框架\h4.1富客戶端\h模塊化RequireJS\h4.2Backbone.js簡介\h4.2.1模型\h4.2.2視圖\h4.2.3集合\h4.2.4與服務器交互\h4.2.5路由表\h4.3Angular.js\h4.3.1數(shù)據(jù)雙向綁定\h4.3.2內置指令\h4.3.3AngularJS中的服務\h4.3.4與RESTFul的API集成\h4.3.5與moko集成\h第5章CSS框架簡介\h5.1Foundation簡介\h常用組件\h按鈕\h5.2BootStrap簡介\h5.2.1布局\h5.2.2常用組件\h第6章客戶端測試框架\h6.1Jasmine簡介\h6.1.1Spy功能\h6.1.2自定義匹配器\h6.2Mocha\h6.2.1Mocha的基本用法\h6.2.2測試異步場景\h第7章現(xiàn)代的前端開發(fā)方式\h7.1Karma簡介\h7.2前端依賴管理\h7.3搭建工程\h7.4測試驅動開發(fā)\h7.5實例Todoify\h7.5.1underscore的一些特性\h7.5.2jQuery插件基礎知識\h7.5.3Todoify\h7.5.4進一步改進\h第8章編寫更容易維護的JavaScript代碼\h8.1一個實例\h8.2重構:更容易測試的代碼\h8.2.1搜索框\h8.2.2發(fā)送請求\h8.2.3結果集\h點過贊的地方\h8.2.4放在一起\h8.3關注點分離:另一種實現(xiàn)方式\h8.3.1搜索服務\h8.3.2結果視圖\h8.3.3搜索框視圖\h8.3.4搜索邏輯\h8.3.5放在一起\h8.3.6更容易測試的代碼\h第9章本地構建\h9.1Ruby中的構建\h9.1.1Rake\h9.1.2Guard\h9.2JavaScript中的構建\h9.2.1Grunt的使用\h9.2.2Gulp的使用\h使用插件\h第10章持續(xù)集成\h10.1環(huán)境搭建\h10.1.1安裝操作系統(tǒng)\h10.1.2安裝Jenkins\h10.1.3安裝rbenv\h10.1.4安裝NodeJS\h10.1.5安裝Xvfb\h安裝瀏覽器\h10.2持續(xù)集成服務器\hJenkins\h10.3與Github集成\h10.3.1Travis\h10.3.2Snap\h第11章單元測試與集成測試\h11.1RSpec單元測試\h11.2集成測試工具Selenium\h11.2.1Selenium-webdriver\h11.2.2Capybara\h11.2.3Cucumber\h11.3搭建Selenium獨立環(huán)境\h11.3.1安裝Selenium\h11.3.2服務腳本\h第12章環(huán)境搭建的自動化\h12.1自動化工具Chef\h12.1.1使用Berkshelf管理cookbook\h12.1.2自動創(chuàng)建用戶\h12.1.3安裝nginx服務器\h12.1.4配置nginx\h配置Rbenv\h第13章應用程序發(fā)布\h13.1使用Heroku發(fā)布應用程序\h發(fā)布第一個應用程序\h13.2發(fā)布到虛擬機環(huán)境\h13.2.1使用密鑰登錄\h13.2.2使用Mina\h13.3服務器典型配置\hWeb服務器\h第14章一個實例(前端部分)\h14.1線框圖\h14.2搜索結果頁面\h14.2.1模板頁面\h14.2.2導航欄\h14.2.3走馬燈\h14.2.4搜索框\h14.2.5目錄側欄\h14.2.6植物列表\h14.2.7分頁器\h14.3詳細信息頁面\h14.4加入JavaScript\h14.4.1moko\h14.4.2AngularJS應用\h14.4.3細節(jié)頁面\h第15章一個實例(后臺部分)\h15.1第一個迭代\h15.1.1配置環(huán)境\h15.1.2定義數(shù)據(jù)\h15.1.3第一次提交\h15.1.4添加數(shù)據(jù)\h15.2發(fā)布到Heroku\h15.2.1環(huán)境準備\h15.2.2添加數(shù)據(jù)庫插件\h15.2.3測試遠程應用\h15.2.4訪問遠程數(shù)據(jù)\h15.2.5導出數(shù)據(jù)\h15.3更進一步\h15.3.1模塊化的Sinatra應用\h15.3.2測試\h第16章一個實例(集成)\h16.1發(fā)布\h16.1.1添加植物頁面\h16.1.2一個奇怪的bug\h16.2添加圖片\h16.2.1后臺API\h16.2.2客戶端上傳文件\h16.3新的問題\h16.4文件存儲\h16.4.1創(chuàng)建分組及用戶\h16.4.2創(chuàng)建S3中的bucket\h16.4.3存儲到云端\h16.4.4部署到Heroku\h附錄AWeb如何工作\hA.1CGI的相關背景\hA.2配置Apache支持CGI\hA.3更進一步\hA.4一個稍微有用的腳本\hA.5更進一步FastCGI\h附錄BAngular.js的測試\hB.1測試Controller\hB.1.1AngularJS的一個典型Controller\hB.1.2測試依賴于Service的Controller\hB.1.3在何處實例化Controller\hB.1.4如何mock一個service\hB.2測試Service\hB.2.1Service的典型示例\hB.2.2$httpBackend服務\hB.2.3Service的測試模板\hB.2.4服務器Moco第1章環(huán)境配置與工具準備這一章中,我列出了一些常用的可以提高工作效率的工具集。這些工具都符合體積小巧而功能強大的特點。學習這些工具,可能需要花費一些時間,但是一旦掌握其基本用法,你將會得到數(shù)倍的回報。簡而言之,它們會節(jié)省你的時間。雖然這些工具完成的具體功能各不一樣,但是它們都展現(xiàn)出了一些共性:(1)關注于一件事,并能很好地完成。(2)可以很容易地和其他應用程序一起工作。(3)體積小巧,支持眾多選項。(4)命令行程序。命令行可以說是專業(yè)程序員最親密的朋友,其重要性再怎么強調也不為過。事實上,當一個受過良好訓練的程序員看到一個GUI應用程序時的第一反應就是:有沒有對應命令行的工具?除了極個別的場景以外,比如海報繪制、廣告設計等,大部分情況下,GUI應用可以做到的工作,命令行工具都可以更好地完成。從文本處理、軟件下載、圖片修改、到定時任務、系統(tǒng)監(jiān)控、報表生成,再到即時通信、郵件收發(fā)等一切計算機可以做的事情,都可以通過命令行工具來完成。1.1ShellUNIX世界中,有這樣一句話:Whilethereisashell,thereisaway,即如果有Shell,就有希望。Shell是下面將會討論的很多工具賴以生存的環(huán)境,也是程序員賴以生存的環(huán)境。我每天花在Shell里的時間,占我工作總時間的70%左右(剩下的時間有20%在Chrome中)。在Shell中,編寫代碼,啟動服務器,連接到遠程機器,運行單元/集成測試,調試錯誤,查看日志,查找文件并處理,等等。所有有關開發(fā)的工作都可以在一個或者多個Shell窗口中完成,如圖1-1所示。圖1-1MacOS下的Terminal應用每個Shell都有各自的配置文件,比如最為流行的Bash(默認的所有主流的Linux發(fā)行版都安裝了Bash)中,用戶配置文件位于用戶主目錄~/.bashrc和~/.bash_profile中。這些配置文件會在用戶登錄時被加載,如果用戶已經(jīng)登錄,又對這些文件做了修改,可以使用命令:$source~/bash_profile
來使其生效。而在眾多的Shell中,zsh是我最喜愛的。如果你是在Ubuntu系統(tǒng)中,通過命令:$apt-getinstallzsh
即可安裝,或者通過編譯源碼的方式安裝。在MacOSX下,可以使用:$brewinstallzsh
來完成安裝(需要你的系統(tǒng)中已經(jīng)安裝了homebrew)。zsh的配置文件位于~/.zshrc中。事實上,有一個開源項目名叫oh-my-zsh,為zsh提供了眾多便利的配置。使用它可以省去很多麻煩的配置。安裝非常簡單:$curl-L/robbyrussell/oh-my-zsh/master/tools/install.sh|sh
然后使用chshzsh來切換到zsh,如圖1-2所示。圖1-2在Terminal中使用zsh替換默認的bashoh-my-zsh擁有豐富的特性,比如大量的插件、主題等。這條命令可以查看已經(jīng)安裝好的插件:$ls~/.oh-my-zsh/plugins
可以通過修改~/.zshrc來啟用各種插件:plugins=(gitosx)
這條配置會啟用git插件和osx插件。使用git插件,shell的提示符會發(fā)生變化:如果你正處于一個git的版本庫中,那么提示符會顯示你所處的分支:?octopressgit:(source)?
上面的輸出說明你正處于source分支,而“x”則表示目前本地已經(jīng)有代碼的改動(這個小“x”會在代碼被提交之后消失)。另外一個常用zsh的插件是autojump。autojump是一個命令行工具,可以用來快速地在系統(tǒng)的目錄中切換。它會記錄用戶通過cd命令去過的所有目錄,并根據(jù)切換到該目錄的頻繁程度為每個目錄加上權重。安裝autojump很容易。如果是在Mac系統(tǒng)下,下面這條命令就可以:$brewinstallautojump
如果是在Linix下,或者想要通過源碼安裝,需要確保系統(tǒng)中已經(jīng)安裝了python(python的2.6以上版本),然后執(zhí)行:$gitclonegit:///joelthelion/autojump.git
$cdautojump
$./install.py
安裝完成之后,需要在~/.zshrc中啟用autojump的插件:為plugins這行加上autojump即可:plugins=(gitosxautojump)
使用起來極為簡便,輸入j加目錄名關鍵字即可跳入該目錄,比如想要跳入路徑中含有ruby的目錄:$jruby
/Users/twer/develop/ruby
如果目錄名關鍵字過于模糊,有多個路徑一起命中的話,autojump會選擇權重高的那一條。$j--stat
如圖1-3所示。圖1-3列出目前已經(jīng)緩存的目錄$joctopress
/Users/twer/blogs/octopress
如果這并不是你的本意,那就需要指定更具體的路徑,如jblogs/octopress或者更簡單的jboctopress??梢酝ㄟ^j--stat查看當前已經(jīng)存儲的目錄,以及各自的權重(如圖1-4所示):$j--stat
圖1-4每個目錄都有對應的權重zsh的一些好用的特性列出當前目錄下所有*.rb文件,深度可以是任意層次(如圖1-5所示):$ls-l**/*.rb
圖1-5列出當前目錄下所有的以rb結束的文件自動補全命令的參數(shù)(<TAB>表示tab鍵):$gitst<TAB>
stash--stashawaychangestodirtyworkingdirectory
status--showworking-treestatus
stripspace--filteroutemptylines
自動補全瀏覽過的網(wǎng)站(如圖1-6所示):$ssh<TAB>
3132
...
$curlhttps://www.<TAB>
.au
.au
...
圖1-6zsh的自動補全zsh的智能補全的另一個例子是,你需要殺掉一個ruby進程,但是又不知道這個進程的id。傳統(tǒng)的做法是:$ps-Af|grepruby
如圖1-7所示。圖1-7查找所有的ruby進程找到對應的進程id,再調用kill-9id來終止該進程。而使用zsh,則可以簡化為killruby<TAB>,然后會得到一個列表,持續(xù)地按<TAB>會在這個列表中切換,直到你選中需要殺掉的進程,然后回車即可,如圖1-8所示。圖1-8使用zsh的自動補全來終止ruby進程批量重命名,比如當前目錄有幾個txt結尾的文件,我們需要將后綴修改為html:$ls
1.txt2.txt3.txt4.txt
$zmv'(*).txt''$1.html'
$ls
1.html2.html3.html4.html
zmv是一個zsh的模塊,我們需要將其加載進來:$autoload-Uzmv
命令zmv'(*).txt''$1.html'中,以txt為后綴的文件名部分被存到了一個分組中,這個分組可以通過$1來獲取。這樣我們就可以將文件命名成任意字符串了:$ls
1.html2.html3.html4.html
$zmv'(*).html''template_$1.html.haml'
$ls
template_1.html.hamltemplate_2.html.hamltemplate_3.html.hamltemplate_4.html.haml
1.2管道當各司其職的、又完全獨立的工具組合在一起的時候,命令行的高效才得以體現(xiàn)。比如使用find命令查找所有的測試文件,如果我們更關心的是有多少個這樣的文件,而不是文件的名稱本身,應該怎么做呢?給find再加上一個統(tǒng)計選項?在UNIX世界里,我們有更好的選擇:管道。命令wc可以用于統(tǒng)計文件中的單詞個數(shù)或者行的個數(shù),比如文件file有100行,那么wc-lfile會輸出100。管道用于將多個命令連接起來,即將上一個程序的輸出作為下一個程序的輸入。比如命令:$find.-name"*.rb"|wc-l
表示,從當前的目錄起,查找所有的ruby文件,并統(tǒng)計其個數(shù)。通過管道|,find命令的輸出變成了wc的輸入,這樣兩個程序就連接了起來。通過管道可以將多個程序連接在一起:$find.-name"*.rb"|xargsbasename
app.rb
notes.rb
mobile.rb
user.rb
factories.rb
feather_spec.rb
notes_spec.rb
spec_helper.rb
user_spec.rb
上面這條命令中,basename命令用于從文件的完整路徑中獲取最后一個“/”之后的內容,比如:$basename"/lightweight-web/sinatra/"
sinatra
$basename"/lightweight-web/sinatra/lib"
lib
$basename"/lightweight-web/sinatra/lib/products.rb"
products.rb
而xargs命令用于將前一條命令的輸出作為后一條命令的參數(shù),比如find命令查找出了當前目錄中包含的所有ruby的相對路徑:$find.-name"*.rb"
./app.rb
./lib/notes.rb
./lib/sinatra/mobile.rb
./lib/user.rb
./spec/factories.rb
./spec/feather_spec.rb
./spec/notes_spec.rb
./spec/spec_helper.rb
./spec/user_spec.rb
上邊的那條帶有xargs的命令就可以解釋為,將查找出來的所有ruby文件的完整路徑名通過xargsbasename過濾,只得到文件名本身。得到了這樣的一個列表之后,我們還可以再使用sort命令對這些文件進行排序:$find.-name"*.rb"|xargsbasename|sort
app.rb
factories.rb
feather_spec.rb
mobile.rb
notes.rb
notes_spec.rb
spec_helper.rb
user.rb
user_spec.rb
還可以將這個命令再擴充為find.-name".rb"|xargsbasename|sort|xargscat,即將sort產生的輸出,又逐行地作為cat命令的參數(shù),這樣就可以查看所有".rb"文件的內容了。而如果文件比較多的話,我們還可以使用分頁工具如more或者less命令來分頁查看:$find.-name"*.rb"|sort|xargscat|less
1.3幾個常用命令1.3.1文件查找命令find著名的編輯器Vim的作者(BramMoolenaar)曾在一次演講中提到如何更高效地學習和使用Vim:(1)觀察自己的動作,并發(fā)現(xiàn)低效的一些操作。(2)查看幫助或者請教周邊的人,如何用更高效的方式來完成。(3)不斷地練習這種高效的方式,使之成為一種習慣。事實上,這種方法可以用以學習其他一切工具。通過觀察,我發(fā)現(xiàn)自己,以及其他程序員在工作中,很多時候都是在做各種各樣的查詢——查找文件、查找文件中的某些關鍵字、查找具有某種特征的目標。完成這項工作有很多種方式,圖形界面無疑是最糟糕的一種。因為有太多可能的選項(按照文件名字的一部分,按照修改時間,按照大小,按照所有者等等),對于一個GUI程序來說,各種條件如何擺放便是一個巨大的挑戰(zhàn)。UNIX世界里經(jīng)典的find命令可以使這個過程變得非常容易,甚至是一種享受。find命令遵循以下模式:$findwhere-to-lookcriteria[what-to-do]
即,從何處開始查找,查找的條件是什么,以及找到之后做什么動作(這一步是可選的,默認的find命令會打印文件的全路徑)。舉一個簡單的例子:$find.-name"*.rb"
這條命令會從當前目錄開始,遞歸遍歷所有的子目錄,查找名字中帶有.rb的文件及目錄(雖然將一個目錄命名為xxx.rb有些奇怪,不過這是合法的)。此處的點號(.)表示當前目錄,即告訴find從當前目錄開始查找,-name參數(shù)指定按照名字查找,而正則表達式".rb"表示所有以“.rb”結尾的字符串。如果找到了匹配項,find命令會打印出該文件相對于當前目錄的路徑。$find.-name"*.rb"
./app.rb
./lib/notes.rb
./lib/sinatra/mobile.rb
./lib/user.rb
./spec/factories.rb
./spec/feather_spec.rb
./spec/notes_spec.rb
./spec/spec_helper.rb
./spec/user_spec.rb
我們還可以使用find.-size+100k來查找文件大小在100k以上的所有文件。最巧妙的是,這些條件是可以拼湊起來使用的:$find.-name"*.rb"-size+100k
表示從當前目錄開始,查找名稱中包含"*.rb",并且大小在100k以上(注意100k前面的加號)的所有文件或目錄。另外,用戶還可以指定多個-size參數(shù):$find.-size+50k-size-100k
這條命令表示查找所有大小在50k到100k之間的文件。如果加上-mtime0,可以查找24小時之內修改的大小在50k到100k之間的文件:$find.-size+50k-size-100k-mtime0
find支持眾多的查詢條件,可以通過查看手冊manfind來得到完整的索引。$find.-size+50k-size-100k-mtime0|xargsls-lh
-rw-r--r--1twerstaff64KFeb719:58./4.5_week.geojson
1.3.2網(wǎng)絡命令curlcurl是UNIX世界里另外一個經(jīng)典的應用程序,它支持眾多的網(wǎng)絡協(xié)議,但是更多時候我們只是使用它實現(xiàn)HTTP協(xié)議部分的功能。借助curl的眾多選項,測試基于HTTP的應用程序顯得非常富有樂趣。最簡單的使用curl的場景是使用curl發(fā)送一次HTTP請求:$curl
<!DOCTYPEhtml>
<htmlxmlns="/1999/xhtml"xml:lang="en-US"lang="en-US">
<head>
<metacharset="utf-8"/>
<metaname="Author"content="AppleInc."/>
<metaname="viewport"content="width=1024"/>
...
這條命令會獲取到一個HTML文檔(即這個站點上的index頁面)。有時候我們僅僅需要獲取HTTP的頭信息,而無需關注頁面本身。此時可以使用-I參數(shù):$curl-I
HTTP/1.1200OK
Server:Apache
Content-Type:text/html;charset=UTF-8
Cache-Control:max-age=379
Expires:Fri,07Feb201410:04:41GMT
Date:Fri,07Feb201409:58:22GMT
Connection:keep-alive
這樣我們會得到一個200OK的響應。如果加上-v參數(shù)就可以看到詳細的信息:比如服務器的IP地址,發(fā)往服務器的HTTP頭信息,以及最終服務器的響應:$curl-I-v
以>開頭的行是curl發(fā)往服務器的數(shù)據(jù),以<開頭的行是服務器的響應,而以*開頭的則是一些日志消息。curl命令的詳細輸出如圖1-9所示。圖1-9curl命令的詳細輸出curl常常用于測試基于HTTP的RESTFul的API。比如通過POST方法,向服務器發(fā)送一段JSON數(shù)據(jù):$curl-XPOSThttp://application/resource-d"{\"name\":\"juntao\"}"
-X參數(shù)表示以何種HTTP動詞來完成此次請求,curl支持所有的HTTP動詞(GET、POST、PUT、DELETE、OPTION等)。-d參數(shù)用來表示有數(shù)據(jù)需要發(fā)送,這個數(shù)據(jù)可以是一段內聯(lián)的字符串,也可以是一個文件。如果是文件,需要指明文件名-d@filename。另外,使用curl可以設置HTTP頭信息,這樣在服務器看來,這個請求就好像是從瀏覽器發(fā)來的一樣,此方式可以繞過一些對網(wǎng)絡爬蟲設置了屏障的站點:$curl-H"User-Agent:Mozilla/5.0(Macintosh;IntelMacOSX10_9_1)AppleWebKit/537.36(KHTML,likeGecko)Chrome/31.0.1650.63Safari/537.36"
這里的User-Agent值是GoogleChrome瀏覽器的用戶代理字符串,也就是說,在服務器看來,這個請求就是通過Chrome瀏覽器發(fā)來的。當然,通過-H參數(shù),我們還可以指定諸如Content-Type:application/json或者Accept:application/json等頭信息,以便提供給服務器更多的信息(比如在服務器端,如果客戶端的請求關注的是HTML,則返回HTML的內容,如果客戶端關注JSON,則返回JSON內容)。使用curl還可以做簡單的登錄操作,比如$curl/users/abruzzi>abruzzi.nologin.json
$curl--user"abruzzi:Password"/users/abruzzi>abruzzi.login.json
選項-ccookie-file可以將網(wǎng)站返回的cookie信息保存到文件中,選項-bcookie-file可以使用這個cookie來做后續(xù)的請求,這樣在服務器看來,這些獨立的請求就變成了連續(xù)的了。$curl-L-ccookieshttp://application/resource
$curl-L-bcookieshttp://application/resource
1.3.3文件搜索grepgrep是用于搜索文件內容的一個命令行工具。它提供了很多參數(shù)使得用戶可以以不同的方式做搜索。比如查看文件spec/factories.rb中是否包含字符串"juntao":$grep"juntao"spec/factories.rb
name'juntao'
email'juntao.qiu@'
加上-n選項會打印出這個字符串所在的行號:$grep-n"juntao"spec/factories.rb
5:name'juntao'
6:email'juntao.qiu@'
如果不知道想要搜索的字符串包含在哪些文件中,可以使用-R參數(shù)搜索當前目錄下所有包含字符串“juntao”的文件,如圖1-10所示。圖1-10遞歸的搜索當前目錄,查找字符串“juntao”比如有些目錄可能并不需要搜索,可以使用選項--exclude-dir來過濾,如圖1-11所示。圖1-11排除目錄“spec”進一步地,如果我們需要查找包含“juntao”或者“abruzzi”的行(這兩個網(wǎng)絡id在很多場合表示的都是同一個人),如圖1-12所示。圖1-12根據(jù)正則表達式查找即通過-E參數(shù)來制定后邊需要搜索的字符串是一個正則表達式("juntao|abruzzi"表示,或者"juntao",或者"abruzzi")。有些時候,僅僅顯示匹配上的行可能還不夠,用戶可能需要該行周圍的信息,這時候可以使用參數(shù)-C來啟用上下文打印功能:$grep-n-E"juntao|abruzzi"-R.--exclude-dir=".git"-C1
--
./abruzzi.nologin.json-22-"location":"China",
./abruzzi.nologin.json:23:"email":"juntao.qiu@",
./abruzzi.nologin.json-24-"hireable":false,
--
此處的參數(shù)-C1表示,打印匹配行周圍的一行,即上一行和下一行。這種用法在日志跟蹤時非常有用。還可以使用參數(shù)-B2打印匹配行之前的兩行和參數(shù)-A2打印匹配之后的兩行。1.3.4定時任務crontabcrontab是UNIX下用來執(zhí)行定時任務的一個守護進程。使用crontab可以定期地執(zhí)行一些腳本,比如每天凌晨2點進行數(shù)據(jù)庫備份;每個小時檢查一次磁盤空間,如果空間小于某個閾值,就發(fā)郵件通知系統(tǒng)管理員;每隔10分鐘啟動筆記本電腦的前置攝像頭,為正在專心解決問題的程序員拍張照片,等等。所有這些需要定期運行,又可以通過計算機程序來完成的任務,都可以交給crontab。crontab的格式:MINHOURDOMMONDOWCMD
列名含義取值范圍MIN分鐘0-59HOUR小時0-23DOM每個月的第幾天1-31MON月份1-12DOW每周的第幾天0-6CMD需要執(zhí)行的命令或者腳本可執(zhí)行腳本比如,8月20日下午4點30分,發(fā)一封郵件給smith.sun@的任務描述起來就是:3016208*/home/juntao/bin/send_mail_to_smith
使用命令crontab-e會進入vi的編輯模式(此時用戶實際上在編輯一個臨時文件),將上面的命令寫入,然后保存退出,就完成了一個任務的注冊??梢允褂胏rontab-l來列出所有當前已經(jīng)注冊的任務。crontab支持定義多個定時任務,當用戶定義多個任務時,只需要再次進入crontab的編輯模式,將新建的任務追加進去即可。crontab還支持定義某個指定范圍的任務,比如在工作時間內,每一個小時檢查一次郵件:0009-18***/home/juntao/bin/check_my_email
如果覺得郵件太影響工作,可以設置成每天的11點半和4點半檢查郵件:3011,16***/home/juntao/bin/check_my_email
每過10分鐘拍一張照片,但是周末除外:*/10***0-4/home/juntao/bin/take_a_photo
總之,使用crontab,可以將那些重復的,容易忘記或者容易犯錯的任務都交給計算機來完成。1.3.5JSON查詢利器jq/提供全球范圍內的地震信息,它還提供了程序訪問的接口,比如下列URL提供上周內,全世界范圍內的震級在里氏4.5級以上的地震信息/earthquakes/feed/v1.0/summary/4.5_week.geojson。數(shù)據(jù)以JSON的形式提供,以方便各種編程語言解析和展現(xiàn),如圖1-13所示。圖1-13瀏覽器中的地震信息(geojson格式)但是問題是這種數(shù)據(jù)往往太大了,展現(xiàn)的時候,可能只需要其中的一小部分,比如我們更關注features這個數(shù)組中的一些內容。在做進一步的解析之前,我們先將遠程的文件保存到本地:$curl-s/earthquakes/feed/v1.0/summary/4.5_week.geojson>4.5_week.geojson
保存之后,可以通過cat4.5_week.geojson來查看該文件的內容,或者通過管道將文件內容交給jq來處理。jq可以處理自己的表達式,比如要查看文件中的features數(shù)組的第一個元素:$cat4.5_week.geojson|jq'.features[0]'
{
"id":"usc000mjye",
"geometry":{
"coordinates":[
167.302,
-15.057,
111.24
],
"type":"Point"
},
"properties":{
"title":"M6.5-27kmEofPort-Olry,Vanuatu",
"type":"earthquake",
"magType":"mwp",
"gap":53,
"rms":1.17,
},
...
}
但是即使這樣,內容也顯得太多了,我們事實上只關心地理信息geometry和properties中的title屬性,那么可以通過jq的過濾器來完成:$cat4.5_week.geojson|jq'.features[0]|{geometry,title:.properties.title}'
{
"title":"M6.5-27kmEofPort-Olry,Vanuatu",
"geometry":{
"coordinates":[
167.302,
-15.057,
111.24
],
"type":"Point"
}
}
其中{geometry,title:.properties.title}定義了一個新的對象,這個對象中geometry保持使用features[0]中的geomeotry,而另一個屬性title,則來源于features[0].properties.title。此時,得到的只是features數(shù)組的第一個元素,如果想要得到所有的元素,并且將最后的結果包裝成一個新的數(shù)組,則需要下列表達式:$cat4.5_week.geojson|jq'[.features[]|{geometry,title:.properties.title}]'
[
...
{
"title":"M4.6-63kmSSWofFereydunshahr,Iran",
"geometry":{
"coordinates":[
49.8711,
32.4082,
10
],
"type":"Point"
}
}
...
]
這樣,數(shù)據(jù)量就得到了大幅地減少,使得后續(xù)的操作可以更加快速。1.4編輯器除了Shell,編輯器可能是程序員使用最為頻繁的工具了。關于編輯器已經(jīng)有過很多次戰(zhàn)爭了,我無意于挑起任何關于工具的論戰(zhàn),本節(jié)僅分享一些個人的使用經(jīng)驗。這里列舉的所有工具,都是基于這樣兩個原則:功能強大且輕量小巧。1.4.1Vim編輯器Vim是一個著名的、小巧的、高可配置性的編輯器,如圖1-14所示。開始學習的時候,Vim中眾多反直覺的操作方式會令人很不適應(hjkl鍵來進行導航,yy表示拷貝光標所在行等),但是一旦理解了這些怪異的命令背后的含義,一切就顯得順理成章了。這里不討論Vim的基本使用方法,這里僅僅列出一些非常好用的插件,以方便實際開發(fā):(1)目錄樹查看:nerdtree。(2)查找文件:ctrlp。(3)代碼片段生成:vim-snipmate。(4)代碼注釋:tcomment。圖1-14配置好的vim編輯器這里重點說明如何安裝Vim的插件。很久之前,安裝Vim插件的方法就是在官網(wǎng)上找到該插件,下載壓縮包,然后解壓到~/.vim目錄中。換言之,就是純手工操作,如果換一臺機器,這些插件又需要重新找,重新下載,過程非常不便。vim-pathogen是一個用來簡化這個過程的工具。安裝vim-pathogen和傳統(tǒng)的插件安裝方式類似:$mkdir-p~/.vim/autoload~/.vim/bundle
$curl-Sso~/.vim/autoload/pathogen.vim\
/tpope/vim-pathogen/master/autoload/pathogen.vim
這條命令會在你的Vim配置目錄(通常位于~/.vim/)中創(chuàng)建兩個新的目錄autoload和bundle,然后下載pathogen.vim到autoload中。安裝完成之后,你需要在.vimrc中加入:executepathogen#infect()
這樣,pathogen本身就安裝完成了,下面我們來看幾個例子,看看它如何快捷地安裝Vim插件:$cd~/.vim/bundle
$gitclone/scrooloose/nerdtree.git
首先切換到~/.vim/bundle目錄,然后將遠程的git庫/scrooloose/nerdtree.git復制到本地的nerdtree目錄即可完成對nerdtree的安裝。pathogen會檢查~/.vim/bundle下的所有子目錄,并加載其為Vim插件。類似地,如果要安裝ctrlp或者tcomment,都可以用同樣的方式:$cd~/.vim/bundle
$gitclone/kien/ctrlp.vim.git
$gitclone/tomtom/tcomment_vim.git
安裝snipmate時步驟會多一些,但是絕對物超所值:$cd~/.vim/bundle
$gitclone/tomtom/tlib_vim.git
$gitclone/MarcWeber/vim-addon-mw-utils.git
$gitclone/garbas/vim-snipmate.git
其實本質上,vim-snipmate只負責在合適的時刻向文件中插入合適的片段,其本身并不存儲片段。因此,我們還需要很多片段模板:$cd~/.vim/bundle
$gitclone/honza/vim-snippets.git
所謂片段,就是一個預定義的模板:snippetdef
def${1:method_name}
${0}
end
上面的模板定義了當你在編輯器中輸入def時,然后按一個擴展鍵(通常是Tab鍵),內容就會自動被替換成:defmethod_name
end
而且,method_name處于選中狀態(tài),你可以將其修改為任意的方法名,然后再按Tab鍵,光標會置于方法體中,并進入編輯狀態(tài)。這個功能可以節(jié)省很多編輯時間。vim-snippets定義了多種語言的片段,而snipmate負責在合適的時機使用這些片段(比如根據(jù)文件名后綴來判斷到底使用哪種語言的片段)。NERDTree是一個用于顯示目錄樹的插件(如圖1-15所示),在實際開發(fā)中,我們不可能只在一個文件中編碼,通常是在一個目錄中,而且這個目錄往往會有數(shù)層。如何方便地將目錄結構可視化?又如何方便地修改這個目錄結構(比如創(chuàng)建新的文件夾,刪除一個目錄,移動一個文件到另一個文件夾等)?圖1-15NERDTree插件在vim的命令模式中,輸入:NERDTree命令,可以看到上圖左側的顯示的目錄樹結構。此時調用m命令得到一個菜單,如圖1-16所示。圖1-16NERDTree的菜單項這個字符界面的菜單提供多種選項,比如我們可以用菜單中的a選項來新建一個文件夾,注意目錄需要以“/”結尾,如圖1-17所示。圖1-17使用NERDTree創(chuàng)建一個目錄這樣就創(chuàng)建了一個文件系統(tǒng)中的目錄support。選擇菜單中的r選項會將選中的目錄用Finder程序打開,如圖1-18所示。圖1-18在Finder中打開目錄CtrlP插件用以快速地查找文件,尤其在大型的項目中會非常有用,而且CtrlP支持模糊查詢,即使你只記得文件名的一部分,它也可以幫你找到需要的文件。在Vim中,使用Ctrl+P快捷鍵進入CtrlP插件,這時候輸入notes,可以看到一個命中了notes的文件列表,如圖1-19所示。圖1-19使用CtrlP快速查找文件CtrlP還附帶了一個很順手的功能CtrlPMRU:最近最多使用的文件名列表,即CtrlP認為,如果需要切換文件,那么最近編輯次數(shù)最多的那個文件最可能是用戶需要的文件。使用Vim,我們可以很容易為這個功能定義一個鍵映射:map<C-X>:CtrlPMRU<CR>
將這行代碼保存在你的Vim配置文件(通常為~/.vimrc)中。然后每次使用Ctrl-X就會看到一個最近最多編輯的文件的列表:{%img/images/2014/02/vim-ctrlp-recent.png%}比如編輯JavaScript時,鍵入ajax,然后鍵入TAB:snippetajax
$.ajax({
url:"${1:url}",
data:"${2:data}",
success:function(){
${0}
}
});
在文件~/.vim/bundle/vim-snippet/snippets/javascript.snippets中,添加一個新的snippet的定義。定義好之后,在編輯JavaScript文件時,輸入ajax<TAB>就會被自動補全為定義好的模板:$.ajax({
url:"url",
data:"data",
success:function(){
}
});
并且,光標置于url中。對應地,定義一個ruby中測試的snippet,需要修改~/.vim/bundle/vim-snippet/snippets/ruby.snippets:snippetdesc
describe"${1:testcontroller}"do
it"${2:shouldhasrouteindex}"do
${0}
end
end
1.4.2SublimeText編輯器SublimeText是一個小巧的編輯器,在Mac和Windows平臺都有對應的版本。它本身是收費軟件,但是其非注冊版在功能上并沒有限制,只是偶爾會在保存文檔時彈出一個窗口,提示你去注冊。但是這個彈出窗口并不會影響使用。目前SublimeText主要有V2和V3兩個版本,V2為穩(wěn)定版。這里的介紹都是基于V2版本。SublimeText提供了豐富的功能,完整地介紹一個現(xiàn)代編輯器的功能已經(jīng)遠遠超出此文的范圍,這里僅列舉其中幾個非常高效的特性:(1)自由跳轉功能。(2)多重選擇模式。(3)文件預覽(無需在新標簽中打開文件,就可以預覽內容)。(4)快速在已經(jīng)打開的文件中切換。(5)眾多的插件支持。事實上,第5項插件機制使得SublimeText在理論上可以做任何事情,比如界面主題的改變,與外部的應用程序集成,等等。SublimeText很方便地支持跳轉,這個功能的快捷鍵為Command+P,在Windows下為Ctrl+P輸入Command+P進入跳轉模式。(1)輸入文件名即可跳轉到該文件,支持模糊匹配,如圖1-20所示。圖1-20在Sublime中根據(jù)文件名查找文件(2)輸入@加函數(shù)名跳轉至該函數(shù)(對于markdown文檔,可以跳轉至指定標題),如圖1-21所示。圖1-21Sublime中根據(jù)函數(shù)名查找文件(3)輸入#加關鍵字可以跳轉至出現(xiàn)該關鍵字的位置。(4)輸入:加行號可以跳轉至指定行號。這些跳轉命令還可以組合使用,如app.rb:20跳轉到app.rb的第20行。mixin#Products跳轉到文件名包含mixin的文件中關鍵字Products所處的位置。在選中一個詞之后,按Command+Ctrl+G可以將當前文檔/代碼中所有出現(xiàn)這個詞的地方都選中。當用戶編輯當前選中的詞時,所有其他的選中也都會隨之改變,如圖1-22所示。圖1-22Sublime中的多處編輯對于Sublime,首先需要安裝的插件是PackageControl,它類似于Vim中的pathogen,用以方便你安裝其他的插件,PackageControl更強大一些,它還可以幫助你管理其他的所有插件。PackageControl支持自動安裝:在站點/installation上選擇Sublime版本,將對應的python代碼復制下來,然后打開Sublime的控制臺(視圖->現(xiàn)實控制臺)中,將內容粘貼進去即可。重啟Sublime之后,你就可以用工具->命令面板(Shift+Command+P)來安裝插件了。在命令面板中輸入install,會看到一個列表,如圖1-23所示。圖1-23安裝插件然后輸入想要安裝的插件名稱,比如jshint(一個用于靜態(tài)檢查JavaScript語法的工具),如圖1-24所示。圖1-24搜索需要安裝的插件選擇你需要的插件,然后安裝即可。插件安裝之后,可以通過命令面板來使用該插件,也可以通過插件本身提供的快捷鍵來使用。1.5程序啟動器應用程序啟動器,或者稱為程序的啟動加速器,可以幫助你快速地找到需要啟動的程序并啟動,比如MacOS下的Alfred或者Windows下的Launchy。1.5.1LaunchyLaunchy可以快速地啟動一個應用程序,比如敲入word即可將MicrosoftWord啟動起來,如圖1-25所示。圖1-25Launchy啟動器1.5.2AlfredAlfred是Mac下的一個程序啟動加速器,它有兩種版本。普通版完全免費,但是功能集合會小一些。收費版允許開發(fā)者自己開發(fā)工作流,從而更大程度地提高效率。免費版本已經(jīng)非常強大,我們來看它的一些基本的特性:(1)找到并啟動應用程序,如圖1-26所示。圖1-26查找并啟動(2)快速查找/打開文件,如圖1-27所示。圖1-27快速打開文件(3)快速根據(jù)內容查找文件,如圖1-28所示。圖1-28在文件中查找(4)可以使用option+command+c來啟動粘貼板記錄器(需要安裝Alfred的付費包Powerpack),如圖1-29所示,它可以記錄最近使用的所有粘貼板記錄,用戶可以選擇其中的一項,然后粘貼到指定位置:圖1-29粘貼板記錄器比如當鍵入的markdown(一種用于快速編寫結構化文檔的標記語言,可以被轉化成HTML等)時,本地的應用程序中沒有對應的匹配,Alfred會提示是否要去網(wǎng)絡上進行搜索,比如看看Google上有解釋是什么等,如圖1-30所示。圖1-30快速啟動谷歌搜索1.6關于Windows從嚴格意義上來看,Windows系統(tǒng)不適合做開發(fā)。Windows是一個容易上手的操作系統(tǒng),但是缺失了太多的支持高效開發(fā)的元素:沒有shell環(huán)境,GUI程序間無法通信,不是一個真正支持多用戶的系統(tǒng),也很難將其作為服務器來使用。在Windows系統(tǒng)上做開發(fā),常常需要付出數(shù)倍的艱辛,但是為了獲得Linux或者Mac系統(tǒng)的自帶功能(而有時根本無法實現(xiàn))。有很多熱心的程序員為方便在Windows系統(tǒng)上開發(fā)做了很多事情,比如cygwin、mingw等工具。有了這些工具,可以為Windows的先天不足提供一些幫助,但是涉及到操作系統(tǒng)功能的時候,如進程管理、進程調度時,又會出現(xiàn)很多問題(比如如何在cmd中將一個進程放到后臺運行,然后在5分鐘之后殺死該進程)。一個最直接的解決方案就是放棄Windows作為開發(fā)環(huán)境:安裝Linux的虛擬機,宿主機Windows可以用來娛樂,而Linux虛擬機用來做開發(fā);將系統(tǒng)換成Linux或者MacOS,然后在系統(tǒng)中安裝一個Windows的虛擬機用來娛樂等。第2章Web應用服務器Web應用服務器是支持動態(tài)內容生成的Web服務器。通常來講,Web服務器指那些可以提供靜態(tài)內容的、建立在HTTP協(xié)議之上的服務器。Web服務器僅僅提供文檔的映射或者說托管的能力,即客戶端可以通過HTTP協(xié)議來請求一些文件資源,這些資源都是預先存在的,如果服務器需要根據(jù)客戶端的請求來生成不同的資源,則需要應用程序來支持。這里說的應用程序可以是任何語言,比如C、Java、Python、Ruby,等等,我們這里選擇Ruby來進行描述。一來是Ruby非常簡單,已經(jīng)存在很多的庫來簡化Web應用程序開發(fā),二來Ruby對DSL的支持非常好,可以寫出非常易讀的代碼。2.1RackRack是一個用于連接支持Ruby的Web服務器和Web框架的程序庫,或者稱為微框架。它非常小巧,可以說是輕量級框架/程序庫中的典范。一方面,Rack包含了不同的Handler來和Web服務器連接(如WEBrick、Mongrel等,這些Web服務器類似于Apachehttpd,但是又可以支持Ruby語言)。另一方面,Rack包含了適配器,用以連接Web框架(Sinatra、Rails等)。Rack程序通常會扮演中間人的角色:當HTTP請求從Web服務器上發(fā)往Web應用程序時,Rack可以做一些數(shù)據(jù)轉化操作;同樣,當響應從Web應用發(fā)往Web服務器時,Rack又可以做一些其他的工作。最簡單的Rack應用程序就是一個Ruby對象。根據(jù)Rack的規(guī)范,這個對象上需要有一個call方法,并且這個方法接收一個參數(shù)(一個Hash)。而call方法需要返回一個包含3個元素的數(shù)組:狀態(tài)碼、HTTP頭信息(一個Hash)以及內容(通常這個內容是一個字符串數(shù)組,或者是一個文件對象)。這個描述聽起來非常拗口,但是用代碼來表示的話就非常清晰了:defproc(env)
[200,{"Content-Type"=>"text/plain"},["Hello,world"]]
end
可以看到,方法proc接收一個參數(shù),并返回一個包含三個元素的數(shù)組。但是此處的proc是一個Ruby的方法,我們需要將這個方法剝離出來,使其成為一個可以響應call的對象:rack_proc=method(:proc)
method方法會將一個Ruby的方法轉換成一個對象,這個對象可以響應call方法。rack_proc對象就是一個Proc對象的實例,它可以響應call方法,接收一個參數(shù)(一個Hash),并且可以返回包含三個元素的數(shù)組。也就是說,它已經(jīng)符合Rack應用程序的標準。事實上,使用Ruby的lambda表達式,我們可以以更簡單的方式做到同樣的事情:rack_proc=lambda{|env|[200,{"Content-Type"=>"text/plain"},["Hello,world"]]}
Rack本質上只是一個簡單的接口規(guī)范,我們此處要討論得更多的是Rack這個gem:一個參考實現(xiàn)和一些方便開發(fā)的工具。Rack的gem中包含了眾多的助手函數(shù),使用這些助手,我們可以很快創(chuàng)建出Web應用程序。安裝rack非常容易,在Gemfile中添加rack,然后執(zhí)行bundleinstall:source''
gem'rack'
安裝好rack之后,我們就可以來編寫第一個簡單的Rack應用了,在irb(Ruby自帶的一個交互式環(huán)境,可以在其中直接編寫Ruby代碼,并求值運行)中輸入:require'rack'
rack_proc=lambda{|env|[200,{"Content-Type"=>"text/plain"},["Hello,world"]]}
Rack::Handler::WEBrick.runrack_proc
語句Rack::Handler::WEBrick.runrack_proc會啟動一個HTTP服務器,并在8080端口監(jiān)聽。當請求到達時,Rack會調用我們的應用程序,也就是函數(shù)rack_proc來產生響應。[2014-02-0523:54:44]INFOWEBrick1.3.1
[2014-02-0523:54:44]INFOruby1.9.3(2012-10-12)[x86_64-darwin12.2.0]
[2014-02-0523:54:44]INFOWEBrick::HTTPServer#start:pid=45429port=8080
此時在瀏覽器地址欄鍵入“http://localhost:8080”就可以看到“Hello,world”的響應了。更方便的方法是可以通過命令行curl命令來查看:$curlhttp://localhost:8080
Hello,world
相比之下,我更喜歡命令行方式,速度也更快。2.1.1rackup好了,實驗成功,接下來我們需要將這些代碼保存到文件中,以便下次使用。上邊提到過,Rack的gem中提供了一個很好用的工具rackup,可以用來啟動符合Rack規(guī)范的應用程序。rackup需要一個配置文件,這個配置文件一般由.ru結尾。我們可以將上面在irb中的實驗代碼存入config.ru文件:require'rack'
rack_proc=lambda{|env|[200,{"Content-Type"=>"text/plain"},["Hello,world"]]}
runrack_proc
注意此處,我們去掉了run方法前面的對象Rack::Handler::WEBrick,rackup自己會知道需要運行在何種環(huán)境,默認的即為WEBrick。保存文件之后,執(zhí)行rackupconfig.ru即可啟動應用程序了。$rackupconfig.ru
[2014-02-0600:15:07]INFOWEBrick1.3.1
[2014-02-0600:15:07]INFOruby1.9.3(2012-10-12)[x86_64-darwin12.2.0]
[2014-02-0600:15:07]INFOWEBrick::HTTPServer#start:pid=45801port=9292
更進一步,我們可以簡化config.ru,將應用程序從文件中移出去:require'rack'
classApp
defcallenv
[200,{"Content-Type"=>"text/plain"},["Hello,world"]]
end
end
移出之后,我們定義了一個新的類App,這個類的所有實例上都會包含方法call,而且是符合Rack規(guī)范的call方法,因此config.ru就被簡化成了:require'./app'
runApp.new
到目前為止,我們的應用程序還沒有任何具體的功能,但是它已經(jīng)具備了一個Rack應用程序所需的所有要素了。我們來對其做一下簡單的擴展:返回客戶端的請求中的所有HTTP頭信息。require'rack'
require'json'
classApp
defcallenv
[200,{"Content-Type"=>"application/json"},[env.to_json]]
end
end
使用rackupconfig.ru啟動服務之后,通過命令行的curl來進行測試,并通過jq命令將輸出的json字符串格式化:$curlhttp://localhost:9292|jq.
{
"REQUEST_PATH":"/",
"HTTP_VERSION":"HTTP/1.1",
"rack.url_scheme":"http",
"rack.run_once":false,
"rack.multiprocess":false,
"rack.multithread":true,
"rack.errors":"#<Rack::Lint::ErrorWrapper:0x007fd1a2830380>",
"rack.input":"#<Rack::Lint::InputWrapper:0x007fd1a2830448>",
"SCRIPT_NAME":"",
"REQUEST_URI":"http://localhost:9292/",
"REQUEST_METHOD":"GET",
"REMOTE_HOST":"localhost",
"REMOTE_ADDR":"",
"QUERY_STRING":"",
"PATH_INFO":"/",
"GATEWAY_INTERFACE":"CGI/1.1",
"SERVER_NAME":"localhost",
"SERVER_PORT":"9292",
"SERVER_PROTOCOL":"HTTP/1.1",
"SERVER_SOFTWARE":"WEBrick/1.3.1(Ruby/1.9.3/2012-10-12)",
"HTTP_USER_AGENT":"curl/7.30.0",
"HTTP_HOST":"localhost:9292",
"HTTP_ACCEPT":"*/*",
"rack.version":[
1,
2
]
}
可以看到,env中包含了客戶端請求的所有信息,比如請求類型、客戶端的User-Agent、查詢字符串(QueryString)以及一些rack自身的信息(這些屬性都以rack.開頭)。Rack還提供了將這些信息解析為Request對象(類似于JavaEE中的HTTPRequest對象)的功能,根據(jù)這個對象,我們可以獲取請求類型,以及客戶端發(fā)送請求時的參數(shù)信息:classApp
defcallenv
req=Rack::Request.new(env)
preq.request_method
preq.params['name']
preq.params['address']
[200,{"Content-Type"=>"application/json"},[env.to_json]]
end
end
此處使用函數(shù)p將解析出來的請求對象中的一些信息打印到控制臺上。比如request_method可以得到請求類型,params['name']可以得到請求字符串中name對應的值。$curlhttp://localhost:9292?name=juntao&address=China
在服務器運行的窗口可以看到這樣的輸出:$rackupconfig.ru
[2014-02-0600:45:05]INFOWEBrick1.3.1
[2014-02-0600:45:05]INFOruby1.9.3(2012-10-12)[x86_64-darwin12.2.0]
[2014-02-0600:45:05]INFOWEBrick::HTTPServer#start:pid=46453port=9292
"GET"
"juntao"
"China"
事實上,一旦我們可以獲得這些信息,就可以做很多事情,比如查詢數(shù)據(jù)庫,生成用于校驗的圖片信息,或者刪除某一個資源文件,等等。對應的,Rack提供了對響應的包裝對象Response,通過對Respnose對象的修改,可以生成最終應用程序的響應。classApp
defcallenv
resp=Rack::Response.new
resp['Content-Type']='application/json'
resp.write"{}"
resp.status=200
resp.finish
end
end
上例中,我們先創(chuàng)建了一個空的Rack::Response對象,然后設置了頭信息、狀態(tài)碼以及響應內容,最后調用resp.finish將生成最終的結果。事實上,與上例的代碼相對應的,我們可以將整個過程內聯(lián)到一行:[200,{'Content-Type':'application/json'},[{}]]但是如果我們寫的不是空對象,或者需要添加的HTTP頭信息又不止一個時,使用Response會更加地便利,而且代碼的可讀性也會提高很多。2.1.2Rack中間件Rack中間件,本質上就是一個個的Rack應用程序,但是Rack支持將這些應用程序組成一個鏈(一個先進后出的棧結構)來調用。即請求經(jīng)過一個中間件處理后,緊接著傳遞給下一個中間件處理,然后再傳遞給下一個,依此類推。這個機制從縱向將請求分離開,每個中間件都相互獨立,而當請求從最后一個中間件流出之時,數(shù)據(jù)已經(jīng)經(jīng)過了完整的處理加工(編碼轉換、權限校驗,等等)。定義一個新的中間件事實上非常簡單,無非就是對一個Rack應用程序的包裝而已:classMyMiddleware
definitialize(app)
@app=app
end
defcall(env)
status,headers,body=@app.call(env)
new_body=[]
new_body<<"prefix..."
new_body<<body.to_s
new_body<<"...suffix"
[status,headers,new_body]
end
end
這個中間件會為經(jīng)過它的應用程序的內容加上頭尾信息,在初始化這個中間件的時候,我們將一個Rack應用程序傳遞進來,并保存到實例變量@app上,而MyMiddleware本身又是一個合法的Rack應用程序(call方法,call方法的參數(shù)以及最后的返回值)。在中間件內部,先調用了@app.call(env)獲得原始的輸出,然后再修改這個結構,最后返回包裝過的結果。使用一個中間件非常簡單,僅僅需要在config.ru中加入use語句即可:require'./app'
require'./my_middleware'
useMyMiddleware
runApp.new
使用curl測試,會得到這樣的輸出:$curlhttp://localhost:9292
prefix...["Hello,world"]...suffix
rackup本質上會將config.ru中的內容包裝成一個大的Rack應用程序,而完成這個動作的是Rack::Builder,比如上例中定義的config.ru:useMyMiddleware
runApp.new
會被rackup轉換成類似于這樣的代碼:app=App.new
builder=Rack::Builder.newdo
useMyMiddleware
runapp
end
Rack::Handler::WEBrick.runbuilder,:Port=>9292
當然,你可以同時使用多個中間件:useMyMiddleware1
useMyMiddleware2
useMyMiddleware3
runApp.new
在rackup中,另外一個強大的功能是路由,即將匹配到某個路徑的請求分發(fā)到對應的Rack應用程序上:require'./app'
require'./my_middleware'
useMyMiddleware
map'/'do
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度鋼結構工程大數(shù)據(jù)分析與決策支持合同3篇
- 展會媒體合作合同(2篇)
- 2025年度環(huán)保項目財務代理與審計合同3篇
- 二零二五版智慧校園信息化建設與運營合同3篇
- 二零二五年新能源發(fā)電場電工勞務及環(huán)保設施合同3篇
- 二零二五年度高等學府外國專家講學合同參考文本3篇
- 二零二五年度出租屋租賃合同范本:租賃押金無息退還協(xié)議3篇
- 二零二五年度機械加工行業(yè)信息安全保護合同2篇
- 2025年度標識標牌照明系統(tǒng)升級改造合同3篇
- 二零二五版機票預訂代理及境外旅游套餐合同5篇
- 疏散樓梯安全要求全解析
- 汽車擾流板產品原材料供應與需求分析
- 臨床醫(yī)學院畢業(yè)實習管理-new-new課件
- 阻燃材料的阻燃機理建模
- PLC控制系統(tǒng)合同(2024版)
- CJT 511-2017 鑄鐵檢查井蓋
- ISO15189培訓測試卷及答案
- JJG(交通) 171-2021 超聲式成孔質量檢測儀檢定規(guī)程
- 氣象衛(wèi)星技術在軍事中的應用
- 配電工作組配電網(wǎng)集中型饋線自動化技術規(guī)范編制說明
- 介入科圍手術期護理
評論
0/150
提交評論