นอกจาก Russian Doll Caching แล้วมี Techniques อื่น Speed Up Performance in Rails Apps คราวนี้เราดู Rails' Built-in Conditional GET Support ซึ่ง Allow Store Rendered Pages in User's Browser Cache
👋 ถ้าชอบอ่าน Performance นอก Caching เราเขียน Ruby (on Rails) Performance มากกว่านี้ Check Out Ruby Performance Monitoring Checklist
The Etag and Last-Modified Headers
ตอน Browser Execute HTTP GET Request Page in Rails App Router Link to Controller Action Controller Request Required Data from Database Render View HTTP Response (with 200 OK Response Code) Sent Back Browser with Rendered HTML from View in Response Body Browser Parse และ Display
ตอน Resource Requested Again Same Pipeline ในบาง Situations Unnecessary เพราะ Page Didn't Change Meantime HTTP Offers ETag และ Last-Modified Headers Using These Browser Store Response Body และ Use Headers Invalidate When Stale
Etags หรือ Entity Tags ใช้ Client-side Cache Validation Think of Them as Cache Keys for HTTP Responses Passed Back to Browser in HTTP Response Header Every Request
~ $ curl -I https://localhost:3000/products/1 HTTP/1.1 200 OK ... ETag: W/"9462d76cc55aeb6249fa990e39231c7c" Last-Modified: Wed, 25 Apr 2018 08:27:04 GMT ...
ถ้า Response Repeated Later Browser Find Existing Response in Cache Use Stored Etag from Last Request as If-None-Match Header Header นี้ Tell Rails App We Already Have This Version in Cache
ถ้า Etag from Request Matches Current One Rails Send 304 Not Modified Response Without Response Body Tell Browser Use One from Local Cache Instead
~ $ curl -i -H 'If-None-Match: W/"9462d76cc55aeb6249fa990e39231c7c"' https://localhost:3000/products/1 HTTP/1.1 304 Not Modified ... ETag: W/"9462d76cc55aeb6249fa990e39231c7c" Last-Modified: Wed, 25 Apr 2018 08:27:04 GMT ...
Conditional GET Requests in Rails
Request Page from Local Rails App See Rails Adds Etag Each Request Automatically Request Same Page Couple Times Row See Etag Changes Each Request
While Rails Generates Etag Each Request Default Uses Digest of Whole Response Body Generate It หมายถึง <%= csrf_meta_tags %> in Layout Throws Etag Off เพราะ CSRF-token Meta Tag Changes Each Request Because That Changes Body Each Request Etag Invalidated Local Cache Marked Stale
Besides That Rails Never Return 304 Not Modified Default เพราะ Local Cache Never Explicitly Marked Fresh in Controller
fresh_when และ stale?
ใช้ Etags from Request Header Conditional GETs ต้อง Explicitly Mark Object in Local Cache as "Fresh" เช่น Page Show Product Keep Cache Fresh As Long As Product และ View Templates Don't Change ทำ 2 Things:
- Explicitly Set Values Make Up Our Etag Using Whole Response Body Require Render Whole Body Check Cached Response Valid Negates Speedup from Caching Page Locally
- Compare Etag from Request Header to One We Predict Before Rendering View Omit Rendering If Match
Rails Comes with Helpers Does Everything For Us Explicitly Base Etag และ Last-Modified Date on Product ใช้ fresh_when
ถ้ามี Explicit respond_to Block ใช้ stale? แทน fresh_when
ตอนนี้ Request Product Page จะ Cache Response Locally Subsequent Requests Same Page Include Etag Tell Rails We Have Cached Response Compared to New Etag If Match Rails Skip Rendering Page Return 304 Not Modified Immediately

Note: Refreshing Page Always Request Uncached Version Page Test Conditional GETs Work Navigate Away Using Link หรือ Back Button Instead
ชอบ Article นี้และ Previous Articles in AppSignal Academy Series ไหม? เรามี More Articles about Caching in Rails Lined Up แตโปรดอย่าลังเล Let Us Know What You'd Like Us to Write About (Caching-related หรือ Otherwise) Next!