Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Optimizing Rails ด้วย Client‑Side Caching: Mastering Conditional GET Requests

นอกจาก Russian doll caching ยังมี techniques อื่นๆ speed up performance ใน Rails apps ครั้งนี้เราจะดู Rails' built-in conditional GET support ซึ่งอนุญาตให้คุณ store rendered pages ใน user's browser cache

👋 และถ้าคุณชอบอ่านเพิ่มเกี่ยวกับ performance นอกจาก caching มีอีกมากมายที่เราเขียนเกี่ยวกับ Ruby (on Rails) performance ดู Ruby performance monitoring checklist ของเราได้

The Etag และ Last-Modified headers

เมื่อ browser ของคุณ execute HTTP GET request สำหรับ page ใน Rails app ของคุณ router จะ link มันไปหนึ่งใน controller actions ของคุณ Controller จะ request required data จาก database และ render view HTTP response (พร้อม 200 OK เป็น response code) จะถูกส่งกลับไป browser พร้อม rendered HTML จาก view ใน response's body สำหรับ browser parse และ display

เมื่อ resource ถูก request อีกครั้ง เราจะผ่าน pipeline เดียวกัน ในบาง situations นี่ unnecessary เพราะ page ไม่ได้เปลี่ยนในช่วงเวลานั้น สำหรับนั้น HTTP เสนอ ETag และ Last-Modified headers ด้วยเหล่านี้ browser สามารถ store response body และใช้ headers เพื่อ invalidate พวกมันเมื่อ stale

Etags หรือ Entity tags ใช้สำหรับ client-side cache validation ดังนั้นคุณสามารถคิดว่าพวกมันเป็น cache keys สำหรับ HTTP responses พวกมันถูกส่งกลับไป browser ใน HTTP response header สำหรับทุก 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 ถูก repeat ภายหลัง browser หา existing response ใน cache และใช้ stored Etag จาก last request เป็น If-None-Match header Header นี้จะบอก Rails app ของเราว่าเรามี version นี้ใน cache แล้ว

ถ้า Etag จาก request match กับ current one Rails จะส่ง 304 Not Modified response โดยไม่มี response body นี่จะบอก browser ให้ใช้จาก local cache แทน

~ $ 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 ใน Rails

ถ้าเรา request page จาก local Rails application เราสามารถเห็นได้ว่า Rails เพิ่ม Etag สำหรับแต่ละ request อัตโนมัติ ถ้าเรา request หน้าเดียวกันหลายครั้งติดกัน เราเห็น Etag เปลี่ยนทุก request

แม้ Rails generate Etag สำหรับแต่ละ request โดยค่าเริ่มต้น มันใช้ digest ของ whole response body เพื่อ generate มัน นี่หมายถึง <%= csrf_meta_tags %> ใน layout ทำให้ Etag ผิด เพราะ csrf-token meta tag เปลี่ยนทุก request เพราะมันเปลี่ยน body สำหรับแต่ละ request Etag จึงถูก invalidate และ local cache ถูก mark stale

นอกจากนั้น Rails จะไม่คืน 304 Not Modified โดยค่าเริ่มต้น เพราะ local cache ไม่ถูก explicitly marked as fresh ใน controller ของเรา

fresh_when และ stale?

เพื่อใช้ Etags จาก request header สำหรับ conditional GETs เราต้อง explicitly mark object ใน local cache ว่า "fresh" ตัวอย่างสำหรับ page ที่แสดง product เราสามารถ keep cache fresh ตราบใดที่ product และ view templates ไม่เปลี่ยน เพื่อทำให้งาน เราจะทำสองอย่าง

  1. เราจะ explicitly ตั้งค่าที่จะทำให้เป็น Etag เนื่องจากใช้ whole response body จะต้อง render whole body เพื่อ check ถ้า cached response valid ซึ่ง negate speedup จาก caching page locally
  2. เราจะ compare Etag จาก request header กับที่เราพยายาม ก่อน render view และเราจะ omit rendering ถ้าพวกมัน match

Rails มาพร้อม helpers ที่ทำทุกอย่างให้เรา เราสามารถ explicitly base Etag และ Last-Modified date บน product โดยใช้ fresh_when

# app/views/products/show.html.erb def show @product = Product.find(params[:id]) fresh_when @product end

ถ้าคุณมี explicit respond_to block ใช้ stale? แทน fresh_when

# app/views/products/show.html.erb def show @product = Product.find(params[:id]) if stale?(@product) respond_to do |format| format.html end end end

ตอนนี้ request หนึ่งใน product pages จะ cache response locally Subsequent requests ไปหน้าเดียวกันจะ include Etag บอก Rails เรามี cached response ซึ่งจะถูก compare กับ new Etag ถ้า match Rails จะ skip rendering page และคืน 304 Not Modified ทันที

Note: การ refresh page จะ request uncached version ของ page เสมอ เพื่อ test ถ้า conditional GETs ทำงาน navigate away ใช้ link หรือ back button แทน

คุณชอบบทความนี้และ previous articles ใน AppSignal Academy series อย่างไร? เรามี articles เกี่ยวกับ caching ใน Rails lined up แต่อย่าลังเลบอกเราว่าอยากให้เราเขียนเกี่ยวกับอะไร (caching-related หรืออื่นๆ) ต่อไป!