HTTP通訊協(xié)議是1種Request-Response (要求-回應(yīng))的流程,客戶端(通常是閱讀器)向伺服器送出1個(gè)HTTP request封包,然后伺服器就回應(yīng)1個(gè)response封包。在上1章中,我們介紹了Rails如何使用路由來分派request到Controller的其中1個(gè)Action。而每一個(gè)Action的任務(wù)就是根據(jù)客戶端傳來的資料與Model互動(dòng),然后回應(yīng)結(jié)果給客戶端。這1章中我們將仔細(xì)介紹負(fù)責(zé)回應(yīng)要求的Controller。
透過rails g controller
指令產(chǎn)生出來的controller都會(huì)繼承自ApplicationController
。因此定義在這里的方法可以被所有Controller取用,你可以在這邊定義1些共用的方法。預(yù)設(shè)的application_controller.rb長的以下:
class ApplicationController < ActionController::Base
protect_from_forgery
end
其中的protect_from_forgery
方法啟動(dòng)了CSRF安全性功能,所有非GET的HTTP
request都必須帶有1個(gè)Token參數(shù)才能存取,Rails會(huì)自動(dòng)在所有表單中幫你插入Token參數(shù),預(yù)設(shè)的Layout中也有1行<%
= csrf_meta_tag %>
標(biāo)簽可讓JavaScript讀取到這個(gè)Token。
但是當(dāng)需要開放API給非閱讀器客戶端時(shí),例如手機(jī)端或第3方利用的回呼(webhook),這時(shí)候候我們會(huì)需要關(guān)閉這個(gè)功能,例如:
class ApisController < ApplicationController
skip_before_action :verify_authenticity_token # 全部ApisController 關(guān)閉檢查
end
我們?cè)?span style="margin:0px; padding:0px 3px; border:0px; font-size:1em; font-family:'andale mono','lucida console'; vertical-align:baseline; line-height:normal">Part1示范過,要產(chǎn)生1個(gè)Controller檔案,請(qǐng)輸入
rails g controller events
如此便會(huì)產(chǎn)生app/controllers/events_controller.rb,依照RESTful設(shè)計(jì)的慣例,所有的Controller命名都是復(fù)數(shù),而檔案名稱依照慣例都是{name}_controller.rb。
1個(gè)Action就是Controller里的1個(gè)Public方法:
class EventsController < ApplicationController
def show
# ...
end
end
在Action方法中我們要處理request,基本上會(huì)做3件事情: 1.搜集request的資訊,例如使用者傳進(jìn)來的參數(shù)2.操作Model來做資料的處理3.回傳response結(jié)果,這個(gè)動(dòng)作稱作render
在Controller的Action當(dāng)中,Rails提供了1些方法可讓你得知此request各種資訊,包括:
在根據(jù)request資訊做好資料處理以后,我們接下來就要回傳結(jié)果給用戶。事實(shí)上,就算你甚么都不處理,Action方法里面空空如也,乃至不定義Action,Rails預(yù)設(shè)也還是會(huì)履行render方法。這個(gè)render方法會(huì)回傳預(yù)設(shè)的Template,依照Rails慣例就是app/views/{controller_name}/{action_name}。如果找不到樣板檔案的話,會(huì)出現(xiàn)Template is missing的毛病。
固然,有時(shí)候我們會(huì)需要自定render,或許是指定不同的Template,或許是不需要Template。這時(shí)候候有以下參數(shù)可使用:
render :text => "Hello"
直接回傳字串內(nèi)容,不使用任何樣板。render :xml => @event.to_xml
回傳XML格式render :json => @event.to_json
回傳JSON格式(再加上:callback
就會(huì)是JSONP )render :nothing => true
空空如也:template
指定Template,例如render
:template => "index"
或可以省略成render "index"
,如果是不同Controller的Template再加上Controller名稱,例如render
"events/index"
。:action
指定同1個(gè)Controller中另外一個(gè)Action的Template (注意到只是使用它的Template,而不會(huì)履行該Action內(nèi)的程式):status
設(shè)定HTTP
status,預(yù)設(shè)是200,也就是正常。其他經(jīng)常使用代碼包括401權(quán)限不足、404找不到頁面、500伺服器毛病等。:layout
可以指定這個(gè)Action的Layout,設(shè)成false即關(guān)掉Layout
補(bǔ)充1提,在特定情況你想把render
的結(jié)果存成1個(gè)字串,例如拿到局部樣板Partials成為1個(gè)字串,這時(shí)候候可以改使用render_to_string
:partial => "foobar"
如果Action不要render任何結(jié)果,而是要使用者轉(zhuǎn)向到別頁,可使用redirect_to
redirect_to events_url
redirect_to :back
回到上1頁。如果需要回傳2進(jìn)位Binary資料,有兩個(gè)方法可使用:
send_data(data, options={})
回傳2進(jìn)位字串,接受以下參數(shù):
data
參數(shù)是2進(jìn)位的字串::filename
使用者貯存下來的檔案名稱:type
預(yù)設(shè)是application/octet-stream:disposition
inline或attachment:status
預(yù)設(shè)是200
send_file(file_location, options={})
回傳1個(gè)檔案,接受以下參數(shù):
file_location
是檔案路徑和檔名::filename
使用者貯存下來的檔案名稱:type
預(yù)設(shè)是application/octet-stream:disposition
inline或attachment:status
預(yù)設(shè)是200不過實(shí)務(wù)上我們很少在上線環(huán)境上直接用Rails來推送靜態(tài)檔案,由于大檔的傳輸時(shí)間會(huì)浪費(fèi)寶貴的Rails運(yùn)算資源。我們會(huì)改用X-Sendfile Header將傳檔的任務(wù)委派給網(wǎng)頁伺服器(例如Apache或Nginx )處理,來下降Rails伺服器的負(fù)擔(dān)。或是搭配第3方云貯存服務(wù)例如AWS S3將傳檔的任務(wù)外包出去。
我們?cè)诘?章RESTful利用程式中曾示范過用法,respond_to
可以用來回應(yīng)不同的資料格式。Rails內(nèi)建支援格式包括有:html,
:text, :js, :css, :ics, :csv, :xml, :rss, :atom, :yaml, :json
等。如果需要擴(kuò)充,可以編輯config/initializers/mime_types.rb這個(gè)檔案。
如果你想要設(shè)定1個(gè)else的情況,你可以用:any
:
respond_to do |format|
format.html
format.xml { render :xml => @event.to_xml }
format.any { render :text => "WTF" }
end
另外,Rails也支援單行的簡單寫法:
respond_to :html, :json, :js
這樣其實(shí)就是:
respond_to do |format|
format.html
format.json
format.js
end
HTTP是1種無狀態(tài)的通訊協(xié)議,為了能夠讓閱讀器能夠在跨request之間記住資訊,Rails提供了Session功能,像是記住登入的狀態(tài)、記住使用者購物車的內(nèi)容等等,都是用Session實(shí)作出來的。
要操作Session,直接操作session
這個(gè)Hash變數(shù)便可。例如:
session[:cart_id] = @cart.id
Rails預(yù)設(shè)采取Cookies
session storage來貯存Session資料,它是將Session資料透過config/secrets.yml的secret_key_base
編碼后放到閱讀器的Cookie當(dāng)中,最大的好處是對(duì)伺服器的效能負(fù)擔(dān)很低,缺點(diǎn)是大小最多4Kb,和資料還是可以透過反編碼后看出來,只是沒法進(jìn)行修改。因此安全性較低,不合適寄存機(jī)密資料。
除??Cookies session storage,Rails也支援其他方式,你可以修改config/initializers/session_store.rb:
:active_record_store
使用資料庫來貯存:mem_cache_store
使用Memcached快取系統(tǒng)來貯存,合適高流量的網(wǎng)站1般來講使用預(yù)設(shè)的Cookies session storage便可,如果對(duì)安全性較高要求,可使用資料庫。如果希望統(tǒng)籌效能,可以斟酌使用Memcached。
采取:active_record_store
的話,必須安裝activerecord-session_store
gem,然后產(chǎn)生sessions資料表:
$ rails g active_record:session_migration
$ rake db:migrate
除??Session,我們也能夠直接操作底層的
上一篇 python 連接各類主流數(shù)據(jù)庫簡單示例
下一篇 ScalersTalk成長會(huì)機(jī)器學(xué)習(xí)小組-深度學(xué)習(xí)第3次學(xué)習(xí)筆記