<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 5.1 控制器中的請求和相應 ## 概要 本課時講解控制器中如何處理傳入的參數和相應,并且介紹在請求和相應的過程中,如何處理請求參數,使用 sesson,設置 etag 緩存和使用 csrf 確保數據來源安全。 ## 知識點 - request - response - params - respond_to - session - cookies - etag - csrf ## 正文 ### 5.1.1 Action Pack [Action Pack](https://github.com/rails/rails/tree/master/actionpack) 是 Rails 種又一個核心的 Gem,它可以處理 web 請求,使用 routes 中定義的規則調用控制器(Controller)及方法(Action),并且自動判斷請求類型,做出對應的相應。 Rails 中的控制器,指的就是處理請求及做出相應。 ### 5.1.2 Request 類 `ActionDispatch::Request` 類是對 web 請求的包裝類,它有兩個常用的方法: ~~~ request.headers["Content-Type"] # => "text/plain" ~~~ `headers` 包含了請求的頭信息。 ~~~ request.parameters ~~~ 它會返回請求的參數,不過我們并不直接使用它,而是使用 `params` 方法獲得,這在稍后介紹。 Request 類的源代碼在[這里](https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb)。 ### 5.1.3 Response 類 `ActionDispatch::Response` 類代表了響應結果,它也有常用的方法,不過我們更經常用的是 Controller 中的 action 和回調。在一些測試代碼中,我們經常使用 response 實例。 比如,我們測試商品刪除之后,會返回到商品列表,我們的測試代碼是: ~~~ RSpec.describe ProductsController, type: :controller do ... describe "DELETE #destroy" do it "redirects to the products list" do product = Product.create! valid_attributes delete :destroy, {:id => product.to_param}, valid_session expect(response).to redirect_to(products_url) end end end ~~~ Request 和 Response 在我們的業務邏輯代碼中并不不常用到,下面介紹的內容,是我們在編寫控制器代碼時,經常遇到的。 ### 5.1.4 strong paramaters Controller 是控制器的概念,所謂控制,指在網絡傳輸中,接收參數和做出相應。Controller 有兩種方式接收參數:GET 和 POST。兩種方式均可通過 `params` 讀取傳遞的內容。 在 Rails3之前的版本中,當接收傳遞的參數,用來更新資源屬性時,可以設定 Model 的屬性白名單,非報名單上的屬性不允許通過參數傳遞的方式修改,比如: ~~~ class User < ActiveRecord::Base attr_accessible :name end ~~~ 在 Rails 4 之后,這個方法轉為 [gem](https://github.com/rails/protected_attributes),不再是 Rails 4 的核心功能,但將在 Rails 5 中重新回到核心功能中。現在,使用 `permit` 方法來過濾參數。使用 scaffold 創建的 Controller 默認使用了該方法: ~~~ class ProductsController < ApplicationController def create @product = Product.new(product_params) ... private def product_params params.require(:product).permit(:name, :price, :description) end end ~~~ `permit` 可以設定關聯關系的屬性: ~~~ params.require(:product).permit(:name, :price, :description, variants_attributes: [:price, :size, :id, :_destroy]) ~~~ `:id` 和 `:_destroy` 適用于上一章介紹的 `accepts_nested_attributes_for` 方法。 ### 5.1.5 respond_to 方法 Controller 響應請求有多種結果,響應返回 `Status Code`,常見的有 200(成功響應),302(跳轉),404(未找到資源),500(內部錯誤)。更多響應 Code 參考 [3.3 視圖中的 AJAX 交互](#)。 一個 controller 的 action 對應一個請求,這樣可以保持我們業務邏輯代碼清晰,易維護。一個 action 可以響應一個請求的多中類型,這在我們第三章里已經有了介紹和演示。 Controller 使用 `respond_to` 方法,針對每一種請求類型,做出響應: ~~~ respond_to do |format| if @product.save format.html { redirect_to @product, notice: 'Product was successfully created.' } format.json { render :show, status: :created, location: @product } else format.html { render :new } format.json { render json: @product.errors, status: :unprocessable_entity } end format.js end ~~~ 當我們處理多個資源時,每個資源的 `create` 和 `update` 等資源方法,大多都具備相同的邏輯代碼。除了特定的業務邏輯,他們都會響應典型的資源操作。 Rails 4.2 之前提供了 `respond_with` 訪問,4.2 之后將它轉為一個 gem,我們安裝這個 gem: ~~~ gem "responders" ~~~ 并且創建文件: ~~~ % rails g responders:install create lib/application_responder.rb insert config/application.rb prepend app/controllers/application_controller.rb insert app/controllers/application_controller.rb create config/locales/responders.en.yml ~~~ 默認,它只支持 :html,因為我們演示時,又使用到了 :json 和 :js,還有 :xml,我們將這些類型添加上: ~~~ class ApplicationController < ActionController::Base self.responder = ApplicationResponder respond_to :html, :xml, :json, :js ~~~ 我們將剛才 `respond_to` 方法改成 `respond_with`,精簡重復的代碼(Dry up your code): ~~~ def create @product = Product.create(product_params) respond_with(@product) end ~~~ 在 [6.4 I18n](#) 中,我們講 I18n 文件做了整理,這里我們把 generator 創建的語言包,按照 6.4 一節中介紹的方式進行管理,并且增加中文提示。如此,我們不必為每個資源創建、修改等操作各自編寫語言提示了。 ### 5.1.6 session 和 cookies 從一個請求到另一個請求,Rails 使用 Session 來保存一些簡單的信息,比如 user_id 等。同時,也可以用 cookies 保存該信息。 當 Rails 項目創建的時候,它會有一個默認的 cookie name,這在 `config/initializers/session_store.rb` 中: ~~~ Rails.application.config.session_store :cookie_store, key: '_rails-practice_session' ~~~ 這里,我們用 `cookie_store` 來儲存 session,當我們在項目中保存 session 的時候,數據會保存在這個 cookie 中。 ![](https://box.kancloud.cn/2015-08-18_55d2e480ac1ea.png) 在 Rails 2 之前,可以 decode 這個內容,查看其中 session 的內容: ~~~ require 'rack' cookie = "WmQyNFliZnprd3..." Rack::Session::Cookie::Base64::Marshal.new.decode(cookie) => {"session_id"=>"d3b17...", "user_id"=>"123", "_csrf_token"=>"rtkofT..."} ~~~ 因為在 Rails 3 中已經增加了 `secret_key_base`,所以無法直接 decode 內容了。 但是,如果單獨使用一個 cookie 來記錄數據,默認是不經過任何加密的: ~~~ cookies[:name] = "Rails" ~~~ ![](https://box.kancloud.cn/2015-08-18_55d2e480bf4c4.png) 如果這個數據不想被暴露,需要單獨加密: ~~~ cookies.signed[:name] = "Rails" cookies.permanent.signed[:name] = "Rails" [1] ~~~ `permanent` 會讓這個 cookie 有20年的有效時間。 Cookie 的 [api](http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html) 文檔在這里。 如果我們在 Cookie 中保存了過多數據,會超出 cookie 的大小限制,這時我們可以更改 session 的保存方式,比如使用 redis,memcached 等。 ~~~ Rails.application.config.session_store :redis_store, servers: { host: "127.0.0.1", port: 6379, namespace: "store_session"} ~~~ 在 [6.2 緩存](#) 中有其他詳細的介紹。 ### 5.1.7 etag Controller 響應的時候,header 中會包含 etag 屬性,根據這個屬性,瀏覽器會判斷該內容是否修改。 ~~~ headers['ETag'] = Digest::MD5.hexdigest(body) ~~~ 但對 Rails 的布局和模板而言,經常包含變動的內容,比如登錄后會顯示用戶名稱,未登錄顯示登錄連接。 并且,body 可能會很大,md5 時間長。 我們可以針對資源,單獨增加 etag: ~~~ def show fresh_when([@product, current_user.try(:id)]) end ~~~ 也可以將它精簡: ~~~ class ProductsController < ApplicationController etag { current_user.try(:id) } ... def show fresh_when(@product) end ~~~ 如果我們僅提供數據,比如 api,[可以去掉模板](http://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-fresh_when): ~~~ fresh_when @product, template: false ~~~ ### 5.1.8 csrf 在 Controller 接收請求數據的時候,安全機制會處理跨站請求偽造(cross-site request forgery,簡稱 CSRF)。在我們的布局(layout)頁面,你可能已經看到這樣一個輔助方法: ~~~ <%= csrf_meta_tags %> ~~~ 打開頁面的源碼,我們可以看到: ~~~ <meta name="csrf-param" content="authenticity_token" /> <meta name="csrf-token" content="O3Li25wJK0buXKRQRX4CzpAWheQIQ4VknCPe3KwNIFkIuUsbBApxl2jVVTd9IcmzR8oHLZI0qZpO39aLdNaBAQ==" /> ~~~ 當我使用表單的輔助方法 `form_for` 和 `form_tag` 時,表單會自動創建一個隱藏控件 ~~~ <input type="hidden" name="authenticity_token" value="GI5YwKDhQA4pMlLRaUlpHugYdL5ygNe3Co6TL8PvZDsrRfEAOOIa36+7o7ZRFqJjP8T2d+j3+0nYcpt4GzTFYw=="> ~~~ 當我們使用 `remote: true` 時,這個控件又消失了,這樣是不是不安全?不,ujs 在提交的時候,為我們自動補充上了 `authenticity_token` 參數。 更多 Rails 安全問題,可以參考這里 [http://guides.ruby-china.org/security.html](http://guides.ruby-china.org/security.html)。 注: 感謝 [Rails 4 - Zombie Outlaws](https://www.codeschool.com/courses/rails-4-zombie-outlaws),本節 3,5 的內容靈感來自。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看