2018/1/3

第十五天:從 Rails 認識 HTTP 協定( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 昨天我們學會了怎麼新增 Route 跟 Controller,並且知道怎麼控制要回應什麼內容給瀏覽器。 今天要使用這兩天學會的東西,我們要來看看瀏覽器到底傳了什麼給 Rails,以及 Rails 傳回什麼給瀏覽器。 # 做一組新的 Route 跟 Controller 我們在 `app/controllers/kamigo_controller.rb` 新增一個 `request_headers` 方法,嘗試把 `request` 中的 `headers` 傳回給瀏覽器。 ``` class KamigoController < ApplicationController def eat render plain: "吃土啦" end def request_headers render plain: request.headers end end ``` 然後在 `config/routes.rb` 加入一行 `get '/kamigo/request_headers', to: 'kamigo#request_headers'`。 ``` Rails.application.routes.draw do get '/kamigo/eat', to: 'kamigo#eat' get '/kamigo/request_headers', to: 'kamigo#request_headers' end ``` 開啟網頁伺服器,並且用瀏覽器打開網頁:[http://localhost:3000/kamigo/request_headers](http://localhost:3000/kamigo/request_headers)。 你會看到: ``` # ``` 表示 `request.headers` 是一個 [ActionDispatch::Http::Headers](http://api.rubyonrails.org/classes/ActionDispatch/Http/Headers.html) 物件,但是其實我們想知道的是他包含的內容是什麼,而不是他是什麼類別的物件。 # 從 Rails 觀察 request.headers 所以我們需要改一下程式: ``` class KamigoController < ApplicationController def eat render plain: "吃土啦" end def request_headers render plain: request.headers.to_h end end ``` 加一個 `to_h` ,試著把物件轉成雜湊陣列看看。 ``` {"rack.version"=>[1, 3],... 下略 180 萬字 ``` 結果是成功了,但是瀏覽器印出了 180 萬個字。 我們先試著忽略內容的部分,看一下他的關鍵字有哪些。 ``` class KamigoController < ApplicationController def eat render plain: "吃土啦" end def request_headers render plain: request.headers.to_h.keys end end ``` 再加一個 `keys` ,試著把雜湊陣列轉成只包含關鍵字的陣列看看。 ``` ["rack.version", "rack.errors", "rack.multithread", "rack.multiprocess", "rack.run_once", "SCRIPT_NAME", "QUERY_STRING", "SERVER_PROTOCOL", "SERVER_SOFTWARE", "GATEWAY_INTERFACE", "REQUEST_METHOD", "REQUEST_PATH", "REQUEST_URI", "HTTP_VERSION", "HTTP_HOST", "HTTP_CONNECTION", "HTTP_CACHE_CONTROL", "HTTP_USER_AGENT", "HTTP_UPGRADE_INSECURE_REQUESTS", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", "HTTP_ACCEPT_LANGUAGE", "HTTP_COOKIE", "HTTP_ALEXATOOLBAR_ALX_NS_PH", "HTTP_IF_NONE_MATCH", "SERVER_NAME", "SERVER_PORT", "PATH_INFO", "REMOTE_ADDR", "puma.socket", "rack.hijack?", "rack.hijack", "rack.input", "rack.url_scheme", "rack.after_reply", "puma.config", "action_dispatch.parameter_filter", "action_dispatch.redirect_filter", "action_dispatch.secret_token", "action_dispatch.secret_key_base", "action_dispatch.show_exceptions", "action_dispatch.show_detailed_exceptions", "action_dispatch.logger", "action_dispatch.backtrace_cleaner", "action_dispatch.key_generator", "action_dispatch.http_auth_salt", "action_dispatch.signed_cookie_salt", "action_dispatch.encrypted_cookie_salt", "action_dispatch.encrypted_signed_cookie_salt", "action_dispatch.cookies_serializer", "action_dispatch.cookies_digest", "action_dispatch.routes", "ROUTES_57612100_SCRIPT_NAME", "ORIGINAL_FULLPATH", "ORIGINAL_SCRIPT_NAME", "action_dispatch.request_id", "action_dispatch.remote_ip", "rack.session", "rack.session.options", "action_dispatch.request.path_parameters", "action_controller.instance", "action_dispatch.request.content_type", "action_dispatch.request.request_parameters", "rack.request.query_string", "rack.request.query_hash", "action_dispatch.request.query_parameters", "action_dispatch.request.parameters", "action_dispatch.request.formats", "rack.request.cookie_hash", "rack.request.cookie_string", "action_dispatch.cookies", "action_dispatch.request.unsigned_session_cookie"] ``` 看起來好多了,但是這不好閱讀,我們試著讓他自己換行。 ``` class KamigoController < ApplicationController def eat render plain: "吃土啦" end def request_headers render plain: request.headers.to_h.keys.join("\n") end end ``` 再加一個 `join("\n")`,試著把陣列轉成字串,並且以 `\n` 作為分隔符號,`\n` 其實是換行的意思。 ``` rack.version rack.errors rack.multithread rack.multiprocess rack.run_once SCRIPT_NAME QUERY_STRING SERVER_PROTOCOL SERVER_SOFTWARE GATEWAY_INTERFACE REQUEST_METHOD REQUEST_PATH REQUEST_URI HTTP_VERSION HTTP_HOST HTTP_CONNECTION HTTP_CACHE_CONTROL HTTP_USER_AGENT HTTP_UPGRADE_INSECURE_REQUESTS HTTP_ACCEPT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_COOKIE HTTP_ALEXATOOLBAR_ALX_NS_PH HTTP_IF_NONE_MATCH SERVER_NAME SERVER_PORT PATH_INFO REMOTE_ADDR puma.socket rack.hijack? rack.hijack rack.input rack.url_scheme rack.after_reply puma.config action_dispatch.parameter_filter action_dispatch.redirect_filter action_dispatch.secret_token action_dispatch.secret_key_base action_dispatch.show_exceptions action_dispatch.show_detailed_exceptions action_dispatch.logger action_dispatch.backtrace_cleaner action_dispatch.key_generator action_dispatch.http_auth_salt action_dispatch.signed_cookie_salt action_dispatch.encrypted_cookie_salt action_dispatch.encrypted_signed_cookie_salt action_dispatch.cookies_serializer action_dispatch.cookies_digest action_dispatch.routes ROUTES_57612100_SCRIPT_NAME ORIGINAL_FULLPATH ORIGINAL_SCRIPT_NAME action_dispatch.request_id action_dispatch.remote_ip rack.session rack.session.options action_dispatch.request.path_parameters action_controller.instance action_dispatch.request.content_type action_dispatch.request.request_parameters rack.request.query_string rack.request.query_hash action_dispatch.request.query_parameters action_dispatch.request.parameters action_dispatch.request.formats rack.request.cookie_hash rack.request.cookie_string action_dispatch.cookies action_dispatch.request.unsigned_session_cookie ``` 我們需要過濾掉不想看的東西,但是現在還是沒有很容易閱讀,我們應該排序一下。 ``` def request_headers render plain: request.headers.to_h.keys.sort.join("\n") end ``` 再加一個 `sort`,試著在轉完陣列後,先排序,再作排版文字。 ``` GATEWAY_INTERFACE HTTP_ACCEPT HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_ALEXATOOLBAR_ALX_NS_PH HTTP_CACHE_CONTROL HTTP_CONNECTION HTTP_COOKIE HTTP_HOST HTTP_IF_NONE_MATCH HTTP_UPGRADE_INSECURE_REQUESTS HTTP_USER_AGENT HTTP_VERSION ORIGINAL_FULLPATH ORIGINAL_SCRIPT_NAME PATH_INFO QUERY_STRING REMOTE_ADDR REQUEST_METHOD REQUEST_PATH REQUEST_URI ROUTES_57612100_SCRIPT_NAME SCRIPT_NAME SERVER_NAME SERVER_PORT SERVER_PROTOCOL SERVER_SOFTWARE action_controller.instance action_dispatch.backtrace_cleaner action_dispatch.cookies action_dispatch.cookies_digest action_dispatch.cookies_serializer action_dispatch.encrypted_cookie_salt action_dispatch.encrypted_signed_cookie_salt action_dispatch.http_auth_salt action_dispatch.key_generator action_dispatch.logger action_dispatch.parameter_filter action_dispatch.redirect_filter action_dispatch.remote_ip action_dispatch.request.content_type action_dispatch.request.formats action_dispatch.request.parameters action_dispatch.request.path_parameters action_dispatch.request.query_parameters action_dispatch.request.request_parameters action_dispatch.request.unsigned_session_cookie action_dispatch.request_id action_dispatch.routes action_dispatch.secret_key_base action_dispatch.secret_token action_dispatch.show_detailed_exceptions action_dispatch.show_exceptions action_dispatch.signed_cookie_salt puma.config puma.socket rack.after_reply rack.errors rack.hijack rack.hijack? rack.input rack.multiprocess rack.multithread rack.request.cookie_hash rack.request.cookie_string rack.request.query_hash rack.request.query_string rack.run_once rack.session rack.session.options rack.url_scheme rack.version ``` 我們需要觀察一下每一個 key 裡面包含的內容,來決定哪些是我們不要的。 ``` def request_headers render plain: request.headers.to_h.map{ |key, value| key + ": " + value.class.to_s }.sort.join("\n") end ``` 我們把 `keys` 改成了 `.map{ |key, value| key + ": " + value.class.to_s}`,map 的意思是把每一筆紀錄都拿去作一個轉換,然後傳回一個陣列。 如果我們是寫成 `.map{ |key, value| key }` 的話,就是每一筆紀錄我們只要保留關鍵字的部分,這樣就等於 `keys`,這兩段程式會有相同的結果。 但是因為我們想要看到更多的東西,所以我們再把 `key` 改寫成 `key + ": " + value.class.to_s`,我希望在每一個 key 後面加一個冒號,然後讓 Rails 告訴我,他們是什麼類型的資料。 得到的結果是這樣: ``` GATEWAY_INTERFACE: String HTTP_ACCEPT: String HTTP_ACCEPT_ENCODING: String HTTP_ACCEPT_LANGUAGE: String HTTP_ALEXATOOLBAR_ALX_NS_PH: String HTTP_CACHE_CONTROL: String HTTP_CONNECTION: String HTTP_COOKIE: String HTTP_HOST: String HTTP_UPGRADE_INSECURE_REQUESTS: String HTTP_USER_AGENT: String HTTP_VERSION: String ORIGINAL_FULLPATH: String ORIGINAL_SCRIPT_NAME: String PATH_INFO: String QUERY_STRING: String REMOTE_ADDR: String REQUEST_METHOD: String REQUEST_PATH: String REQUEST_URI: String ROUTES_57612100_SCRIPT_NAME: String SCRIPT_NAME: String SERVER_NAME: String SERVER_PORT: String SERVER_PROTOCOL: String SERVER_SOFTWARE: String action_controller.instance: KamigoController action_dispatch.backtrace_cleaner: Rails::BacktraceCleaner action_dispatch.cookies: ActionDispatch::Cookies::CookieJar action_dispatch.cookies_digest: NilClass action_dispatch.cookies_serializer: Symbol action_dispatch.encrypted_cookie_salt: String action_dispatch.encrypted_signed_cookie_salt: String action_dispatch.http_auth_salt: String action_dispatch.key_generator: ActiveSupport::CachingKeyGenerator action_dispatch.logger: ActiveSupport::Logger action_dispatch.parameter_filter: Array action_dispatch.redirect_filter: Array action_dispatch.remote_ip: ActionDispatch::RemoteIp::GetIp action_dispatch.request.content_type: NilClass action_dispatch.request.formats: Array action_dispatch.request.parameters: ActiveSupport::HashWithIndifferentAccess action_dispatch.request.path_parameters: Hash action_dispatch.request.query_parameters: ActiveSupport::HashWithIndifferentAccess action_dispatch.request.request_parameters: ActiveSupport::HashWithIndifferentAccess action_dispatch.request.unsigned_session_cookie: Hash action_dispatch.request_id: String action_dispatch.routes: ActionDispatch::Routing::RouteSet action_dispatch.secret_key_base: String action_dispatch.secret_token: NilClass action_dispatch.show_detailed_exceptions: TrueClass action_dispatch.show_exceptions: TrueClass action_dispatch.signed_cookie_salt: String puma.config: Puma::Configuration puma.socket: TCPSocket rack.after_reply: Array rack.errors: IO rack.hijack: Puma::Client rack.hijack?: TrueClass rack.input: Puma::NullIO rack.multiprocess: FalseClass rack.multithread: TrueClass rack.request.cookie_hash: Hash rack.request.cookie_string: String rack.request.query_hash: Hash rack.request.query_string: String rack.run_once: FalseClass rack.session.options: ActionDispatch::Request::Session::Options rack.session: ActionDispatch::Request::Session rack.url_scheme: String rack.version: Array ``` 讓我們簡化一下程式碼 ``` def request_headers render plain: request.headers.to_h.map{ |key, value| "#{key}: #{value.class}" }.sort.join("\n") end ``` `"#{key}: #{value.class}"` 是更加簡潔的表示法,用雙引號包裝的字串可以作變數的代換,語法是 `#{變數的名字}`,這種寫法的程式碼會更好閱讀。 看起來那些 `key` 包含 `action_controller`、`action_dispatch`、`puma`、`rack` 的資料都是我們不想看到的,因為他們看起來像是 Rails 這邊才產生的資料,而不是瀏覽器傳來的資料。 我發現這些我們不想要的 key 都包含 `.`,讓我們把在 `key` 包含 `.` 的資料都過濾掉。 ``` def request_headers render plain: request.headers.to_h.reject{ |key, value| key.include? '.' }.map{ |key, value| "#{key}: #{value.class}" }.sort.join("\n") end ``` reject 可以過濾資料,滿足條件 `key.include? '.'` 的資料就沒有辦法進到 map。 得到的結果是這樣: ``` GATEWAY_INTERFACE: String HTTP_ACCEPT: String HTTP_ACCEPT_ENCODING: String HTTP_ACCEPT_LANGUAGE: String HTTP_ALEXATOOLBAR_ALX_NS_PH: String HTTP_CACHE_CONTROL: String HTTP_CONNECTION: String HTTP_COOKIE: String HTTP_HOST: String HTTP_UPGRADE_INSECURE_REQUESTS: String HTTP_USER_AGENT: String HTTP_VERSION: String ORIGINAL_FULLPATH: String ORIGINAL_SCRIPT_NAME: String PATH_INFO: String QUERY_STRING: String REMOTE_ADDR: String REQUEST_METHOD: String REQUEST_PATH: String REQUEST_URI: String ROUTES_57612100_SCRIPT_NAME: String SCRIPT_NAME: String SERVER_NAME: String SERVER_PORT: String SERVER_PROTOCOL: String SERVER_SOFTWARE: String ``` 現在應該可以試試看從顯示資料的類別改成顯示完整資料了。 ``` def request_headers render plain: request.headers.to_h.reject{ |key, value| key.include? '.' }.map{ |key, value| "#{key}: #{value}" }.sort.join("\n") end ``` 看起來像這樣: ``` GATEWAY_INTERFACE: CGI/1.2 HTTP_ACCEPT: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 HTTP_ACCEPT_ENCODING: gzip, deflate, br HTTP_ACCEPT_LANGUAGE: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,ja;q=0.6 HTTP_ALEXATOOLBAR_ALX_NS_PH: AlexaToolbar/alx-4.0 HTTP_CACHE_CONTROL: max-age=0 HTTP_CONNECTION: keep-alive HTTP_COOKIE: _blog_session=RG5tTnJ2eUIyMkFCUFV1UHFaMDhHbXpYekJXbFhQQlBiRlk1UEhucUkvV0IwcDNtV09sNUJuVTJWOS9RU2cweTgxY0Q1TGQ5L21GRWNmS1Z6RmdEa3cxdmxFUnZPOEJObVN3ck10R3Frc2ZOWXBDT2hNY0VZUUg0RHowNlJuazFXeWJXZE5sNjlsTUFBMG12QVJNRmVnPT0tLXo3dEJjUFJtbzRjSy9HODVNcVJRRVE9PQ%3D%3D--02e477b161398d92622542cb43d8b515892b8c59; _ironman_session=SzRPTlE1VytFbFgwRUkxMHlXaDFUVlpqdzN4ekt1eVFtUFpBbmtxNUw0UFd6cytjNkI1MlBOdC9zcnBkejNUMmxLa1MzdnV6Z0dselhHOTEzSUtJTDlrU241empqS1BmanNHSTBLd1VnVzlHV2pDZis4QVVRUk5xandJaGpPNml5VHlHUTI5ZXNCa1NZdHNrNzBYT0lnPT0tLW5salNpWUNVRmlxbUI1U1ZLdXhwMGc9PQ%3D%3D--c56c1473a20c57c62c66a215e07fa14dd6f7fb94 HTTP_HOST: localhost:3000 HTTP_IF_NONE_MATCH: W/"d220fb78d8ab10894ccdd2ef500f5ac8" HTTP_UPGRADE_INSECURE_REQUESTS: 1 HTTP_USER_AGENT: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36 HTTP_VERSION: HTTP/1.1 ORIGINAL_FULLPATH: /kamigo/request_headers ORIGINAL_SCRIPT_NAME: PATH_INFO: /kamigo/request_headers QUERY_STRING: REMOTE_ADDR: 127.0.0.1 REQUEST_METHOD: GET REQUEST_PATH: /kamigo/request_headers REQUEST_URI: /kamigo/request_headers ROUTES_57612100_SCRIPT_NAME: SCRIPT_NAME: SERVER_NAME: localhost SERVER_PORT: 3000 SERVER_PROTOCOL: HTTP/1.1 SERVER_SOFTWARE: puma 3.11.0 Love Song ``` 這應該就是從瀏覽器那邊傳來的全部內容了,我們可以用瀏覽器的 `F12` 看一下差異。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVLQmK5-8hobOxHwM7fDPKwozabp4QBB9nD5y1M7uWUnAaoTC26qgdazr63oKr1QUt9wkA-fiJDXi8o0RsPvhj3fUCCoFsre9sLFP2mq84JNUx93Jx-yWeLfeUmbQ06-LUZF3Elf0CdVs/s1600/1.jpg) 因為這樣我們無法同時看到兩邊的結果,所以需要調整一下開發人員工具的位置,把他調到右側的話會比較恰當。 先點一下這裡: ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi17I9Fn8peVszVuVCgrMpIzaXYW81_aPzQLwIxaecUaWtn9I1ktlyTrvsPUR7WlEhlT9PPzrgeEa45C_bX4L-rTUGbh-hg6orDO-IR0Ih_92jaqiQqovyUOo9wHhZ8HKe-_KaLlpWxZOo/s1600/2.jpg) 再點一下這裡: ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiSl6Rh2CGVY5PgklfbthWbO1HEtakh-mo6EmmpD61LYt-lO8LknqHYh8rLmA0USMTb-tQx7RMFrvOoduJkiAsFNizUiYprtxxviQq-L46dpZPk8OIL6lInWX0jgA0CgYhUui_pHrpa2rg/s1600/3.jpg) 點完之後應該會變成這樣: ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgodGMjV9ohQIhJfHwtTraSHzSa5huE3sDYkq3iwLYrxFRooCd0I30fyBoXDtoKLEo6LVYq9_w6oE9Locc26T1JG414bQGzDhwjzMRxtnSSMMgkm9SShxDA-lUSzaSPOwmV3t7hO7Ycp6Y/s1600/4.jpg) 仔細一看,發現這兩塊是一樣的: ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_HKxX1Svx8CCBpNTgJnmav1jkJ71BN3c7xdOWaIKIUHHWKc0s07lZl8wvIFL2Aip8tSF2t0G-y3CDfWInp9uTUGJvQsvKtgWuo9X18ycAyRDIKcdIMukDnsQpibHVZ52KVbgVOL6Zscw/s1600/5.jpg) # 從 Rails 觀察 request.body 再作一組 Route 和 Controller Action。 Route: ``` get '/kamigo/request_body', to: 'kamigo#request_body' ``` Action: ``` def request_body render plain: request.body end ``` 用瀏覽器連過去看:[http://localhost:3000/kamigo/request_body](http://localhost:3000/kamigo/request_body),發現是 `#`,表示瀏覽器傳了一個空的 request body 過來,因為他是來下載網頁,不是上傳資料。如果是上傳資料的話,就會在 request body 有東西了。 # 從 Rails 觀察 response.headers 再作一組 Route 和 Controller Action。 Route: ``` get '/kamigo/response_headers', to: 'kamigo#response_headers' ``` Action: ``` def response_headers render plain: response.headers.to_h.map{ |key, value| "#{key}: #{value}" }.sort.join("\n") end ``` 用瀏覽器連過去看:[http://localhost:3000/kamigo/response_headers](http://localhost:3000/kamigo/response_headers)。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHNFQ0c4JSoIiOcWfbd23S1W32PgGer8tRw5LxDgPYe588Q_49amNbEyTZNzAv5fgyMLEtSNu3SheQSAyGrckphvd-SWOZ708uFxgQKr3LMDe98HuLyJ9HEFUF-x9Q956Uy45SJWWMI4g/s1600/6.jpg) 資料少很多,這表示 Rails 回傳的東西,不是全放在 `response.headers`,不過這不是很重要,知道有 `response` 這個東西就行了。 我們可以試著加一個 header 看看: ``` def response_headers response.headers['5566'] = 'QQ' render plain: response.headers.to_h.map{ |key, value| "#{key}: #{value}" }.sort.join("\n") end ``` ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW05FXWJNo1QOU3mDjAEhbHTKH97KppDbmgNZwglXEBiAKftpJiOf_5cUTmtYOpMj7khUSAofEvxRrg9sjM2pHsYzD8V5utjztugCaofwIyxPiaEsnNTK3FiMacbwYGf8mY5YRK2SuTvQ/s1600/7.jpg) 哈哈哈哈ㄚ哈 # 從 Rails 觀察 response.body 再作一組 Route 和 Controller Action。 Route: ``` get '/kamigo/response_body', to: 'kamigo#show_response_body' ``` Action: ``` def show_response_body render plain: response.body end ``` 這裡我們不能用 `response_body` ,因為 `response_body` 已經被 Rails 用掉了,我們再用的話會出事,所以這邊稍微改一下名字。 用瀏覽器連過去看:[http://localhost:3000/kamigo/response_body](http://localhost:3000/kamigo/response_body)。 這樣會看到空的結果,因為我們傳回的內容就是 `response.body`,但此時的 `response.body` 其實還是空值。 所以我們必須改變一下觀察的方法,其實我們可以透過小黑框來觀察 Rails 的目前狀況。 在程式碼當中加入 `puts "媽我在這 \\( ̄▽ ̄)/"` 意思是把 `媽我在這 \\( ̄▽ ̄)/` 顯示在小黑框上。 ``` def show_response_body puts "媽我在這 \\( ̄▽ ̄)/" render plain: response.body end ``` 當有人開啟網頁 [http://localhost:3000/kamigo/response_body](http://localhost:3000/kamigo/response_body),就會在小黑框看到這個結果: ``` Started GET "/kamigo/response_body" for 127.0.0.1 at 2018-01-03 03:46:48 +0800 Processing by KamigoController#show_response_body as HTML 媽我在這 \( ̄▽ ̄)/ Rendering text template Rendered text template (0.0ms) Completed 200 OK in 2ms (Views: 0.8ms) ``` 所以我們利用這種方式觀察,現在把程式改成這樣: ``` def show_response_body puts "===這是設定前的response.body:#{response.body}===" render plain: "虎哇花哈哈哈" puts "===這是設定後的response.body:#{response.body}===" end ``` 當有人開啟網頁 [http://localhost:3000/kamigo/response_body](http://localhost:3000/kamigo/response_body),就會在小黑框看到這個結果: ``` Started GET "/kamigo/response_body" for 127.0.0.1 at 2018-01-03 03:51:40 +0800 Processing by KamigoController#show_response_body as HTML ===這是設定前的response.body:=== Rendering text template Rendered text template (0.0ms) ===這是設定後的response.body:虎哇花哈哈哈=== Completed 200 OK in 16ms (Views: 11.5ms) ``` # 總結 那個要抄程式碼的,都幫你整理好了。 ### app/controllers/kamigo_controller.rb ``` class KamigoController < ApplicationController def eat render plain: "吃土啦" end def request_headers render plain: request.headers.to_h.reject{ |key, value| key.include? '.' }.map{ |key, value| "#{key}: #{value}" }.sort.join("\n") end def response_headers response.headers['5566'] = 'QQ' render plain: response.headers.to_h.map{ |key, value| "#{key}: #{value}" }.sort.join("\n") end def request_body render plain: request.body end def show_response_body puts "===這是設定前的response.body:#{response.body}===" render plain: "虎哇花哈哈哈" puts "===這是設定後的response.body:#{response.body}===" end end ``` ### config/routes.rb ``` Rails.application.routes.draw do get '/kamigo/eat', to: 'kamigo#eat' get '/kamigo/request_headers', to: 'kamigo#request_headers' get '/kamigo/request_body', to: 'kamigo#request_body' get '/kamigo/response_headers', to: 'kamigo#response_headers' get '/kamigo/response_body', to: 'kamigo#show_response_body' end ``` ### 網址 [http://localhost:3000/kamigo/request_headers](http://localhost:3000/kamigo/request_headers) [http://localhost:3000/kamigo/request_body](http://localhost:3000/kamigo/request_body) [http://localhost:3000/kamigo/response_headers](http://localhost:3000/kamigo/response_headers) [http://localhost:3000/kamigo/response_body](http://localhost:3000/kamigo/response_body) 今天就講到這裡。 嗯?今天是不是講太多了?

沒有留言: