นอกจากการแคชตุ๊กตารัสเซียแล้ว ยังมีเทคนิคเพิ่มเติมในการเร่งประสิทธิภาพในแอป Rails คราวนี้เราจะดูการรองรับ GET แบบมีเงื่อนไขในตัวของ Rails ซึ่งช่วยให้คุณจัดเก็บหน้าที่แสดงผลในแคชของเบราว์เซอร์ของผู้ใช้
👋 และหากคุณต้องการอ่านเพิ่มเติมเกี่ยวกับประสิทธิภาพนอกแคช ยังมีอีกมากมายที่เราเขียนเกี่ยวกับประสิทธิภาพของ Ruby (on Rails) ให้ดูที่รายการตรวจสอบการตรวจสอบประสิทธิภาพของ Ruby
ส่วนหัว Etag และ Last-Modified
เมื่อเบราว์เซอร์ของคุณดำเนินการคำขอ HTTP GET สำหรับหน้าในแอป Rails ของคุณ เราเตอร์จะเชื่อมโยงไปยังการดำเนินการควบคุมอย่างใดอย่างหนึ่งของคุณ ผู้ควบคุมจะขอข้อมูลที่จำเป็นจากฐานข้อมูลและแสดงผลมุมมอง การตอบสนอง HTTP (ด้วย 200 OK
เป็นรหัสตอบกลับ) จากนั้นจึงส่งกลับไปที่เบราว์เซอร์ด้วย HTML ที่แสดงผลจากมุมมองในเนื้อหาของการตอบสนองเพื่อให้เบราว์เซอร์ของคุณแยกวิเคราะห์และแสดงผล
เมื่อมีการร้องขอทรัพยากรอีกครั้ง เราจะดำเนินการตามไปป์ไลน์เดียวกัน ในบางสถานการณ์ สิ่งนี้ไม่จำเป็นเนื่องจากหน้าไม่เปลี่ยนแปลงในระหว่างนี้ เพื่อสิ่งนี้ HTTP เสนอ ETag และ แก้ไขล่าสุด ส่วนหัว เมื่อใช้สิ่งเหล่านี้ เบราว์เซอร์สามารถจัดเก็บเนื้อหาการตอบสนอง และใช้ส่วนหัวเพื่อทำให้เป็นโมฆะได้เมื่อพวกมันค้าง
Etags , หรือ แท็กเอนทิตี ใช้สำหรับการตรวจสอบแคชฝั่งไคลเอ็นต์ คุณจึงมองว่าเป็นแคชคีย์สำหรับการตอบกลับ HTTP ได้ จะถูกส่งกลับไปยังเบราว์เซอร์ในส่วนหัวการตอบสนอง HTTP สำหรับทุกคำขอ
~ $ 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
...
หากมีการตอบกลับซ้ำในภายหลัง เบราว์เซอร์จะค้นหาการตอบสนองที่มีอยู่ในแคชและใช้ Etag ที่เก็บไว้จากคำขอล่าสุดเป็น If-None-Match
หัวข้อ. ส่วนหัวนี้จะบอกแอป Rails ของเราว่าเรามีเวอร์ชันนี้อยู่ในแคชแล้ว
หาก Etag จากคำขอตรงกับปัจจุบัน Rails จะส่ง 304 Not Modified
การตอบสนองโดยไม่มีร่างกายตอบสนอง การดำเนินการนี้จะบอกให้เบราว์เซอร์ใช้เบราว์เซอร์จากแคชในเครื่องแทน
~ $ 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
...
คำขอ GET แบบมีเงื่อนไขใน Rails
หากเราขอหน้าจากแอปพลิเคชัน Rails ในพื้นที่ เราจะเห็นว่า Rails เพิ่ม Etag สำหรับแต่ละคำขอโดยอัตโนมัติ หากเราขอหน้าเดียวกันสองครั้งติดต่อกัน เราจะเห็นการเปลี่ยนแปลง Etag สำหรับแต่ละคำขอ
แม้ว่า Rails จะสร้าง Etag สำหรับแต่ละคำขอโดยค่าเริ่มต้น แต่จะใช้ไดเจสต์ของเนื้อหาการตอบสนองทั้งหมดเพื่อสร้าง นี่หมายถึง <%= csrf_meta_tags %>
ในเลย์เอาต์จะทิ้ง Etag ออก เนื่องจากเมตาแท็ก csrf-token เปลี่ยนแปลงสำหรับแต่ละคำขอ เนื่องจากนั่นเปลี่ยนเนื้อความสำหรับแต่ละคำขอ Etag จะใช้ไม่ได้และแคชในเครื่องถูกทำเครื่องหมายว่าเก่า
นอกจากนั้น Rails จะไม่ส่งคืน 304 Not Modified
โดยค่าเริ่มต้น เนื่องจากแคชในเครื่องจะไม่ถูกทำเครื่องหมายว่าใหม่อย่างชัดแจ้งในคอนโทรลเลอร์ของเรา
fresh_when
และ stale?
ในการใช้ Etags จากส่วนหัวของคำขอสำหรับ GET แบบมีเงื่อนไข เราจำเป็นต้องทำเครื่องหมายวัตถุในแคชในเครื่องเป็น "สด" อย่างชัดเจน ตัวอย่างเช่น สำหรับหน้าที่แสดงผลิตภัณฑ์ เราสามารถรักษาแคชให้สดใหม่ได้ตราบเท่าที่ผลิตภัณฑ์และเทมเพลตมุมมองไม่เปลี่ยนแปลง เพื่อให้ได้ผล เราจะทำสองสิ่ง
- เราจะกำหนดค่าที่จะประกอบขึ้นเป็น Etag ของเราอย่างชัดเจน เนื่องจากการใช้เนื้อหาการตอบสนองทั้งหมดจะทำให้เราต้องแสดงเนื้อหาทั้งหมดเพื่อตรวจสอบว่าการตอบสนองที่แคชไว้นั้นถูกต้องหรือไม่ ซึ่งขัดขวางการเร่งความเร็วจากการแคชหน้าในเครื่อง
- เราจะเปรียบเทียบ Etag จากส่วนหัวของคำขอกับที่เราคาดการณ์ไว้ ก่อน แสดงมุมมอง และเราจะละเว้นการแสดงผลหากตรงกัน
Rails มาพร้อมกับตัวช่วยที่ทำทุกอย่างเพื่อเรา เราสามารถกำหนด Etag และวันที่แก้ไขล่าสุดบนผลิตภัณฑ์ได้อย่างชัดเจนโดยใช้ fresh_when
.
# app/views/products/show.html.erb
def show
@product = Product.find(params[:id])
fresh_when @product
end
หากคุณมี respond_to
. ที่ชัดเจน บล็อก ใช้ 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
ตอนนี้ การขอหน้าผลิตภัณฑ์หน้าใดหน้าหนึ่งจะแคชการตอบกลับในเครื่อง คำขอใดๆ ที่ตามมาในหน้าเดียวกันจะรวม Etag เพื่อบอก Rails ว่าเรามีการตอบสนองที่แคชไว้ ซึ่งจะถูกนำไปเปรียบเทียบกับ Etag ใหม่ หากตรงกัน Rails จะข้ามการแสดงผลหน้าและส่งคืน 304 Not Modified
ทันที
หมายเหตุ :การรีเฟรชหน้าจะขอหน้าเวอร์ชันที่ไม่ได้แคชเสมอ หากต้องการทดสอบว่า GET แบบมีเงื่อนไขของคุณใช้งานได้หรือไม่ ให้ไปที่ลิงก์หรือใช้ปุ่มย้อนกลับแทน
คุณชอบบทความนี้และบทความก่อนหน้าในซีรีส์ AppSignal Academy อย่างไร เรามีบทความเพิ่มเติมเกี่ยวกับการแคชใน Rails เรียงกัน แต่โปรดอย่าลังเลที่จะแจ้งให้เราทราบว่าคุณต้องการให้เราเขียนเกี่ยวกับอะไร (เกี่ยวกับการแคชหรืออย่างอื่น) ต่อไป!