ฉันสับสนเกี่ยวกับการแคช HTTP

ฉันกำลังคิดถึงการอ่านและเขียนเป็นชุดในสภาพแวดล้อม RESTful และฉันคิดว่าฉันตระหนักว่าฉันมีคำถามที่กว้างขึ้นเกี่ยวกับการแคช HTTP (ด้านล่างฉันใช้เครื่องหมายจุลภาค (",") เพื่อคั่น ID เรกคอร์ดหลายรายการ แต่รายละเอียดนั้นไม่ได้เฉพาะเจาะจงสำหรับการสนทนา)

ฉันเริ่มต้นด้วยปัญหานี้:

1. Single GET ใช้งานไม่ได้โดยการอัพเดตแบบแบตช์

GET /farms/123         # get info about Old MacDonald's Farm
PUT /farms/123,234,345 # update info on Old MacDonald's Farm and some others
GET /farms/123

เซิร์ฟเวอร์แคชที่อยู่ระหว่างไคลเอ็นต์และเซิร์ฟเวอร์ Farms ทราบได้อย่างไรว่าแคชของ /farms/123 เป็นโมฆะเมื่อเห็น PUT

จากนั้นฉันก็รู้ว่านี่ก็เป็นปัญหาเช่นกัน:

2. Batch GET ใช้งานไม่ได้โดยการอัปเดตเดี่ยว (หรือแบทช์)

GET /farms/123,234,345 # get info about a few farms
PUT /farms/123         # update Old MacDonald's Farm
GET /farms/123,234,345

แคชรู้ได้อย่างไรว่าจะทำให้หลายฟาร์ม GET เป็นโมฆะเมื่อเห็นว่า PUT ผ่านไป

ดังนั้นฉันจึงคิดว่าปัญหาจริงๆ อยู่ที่การดำเนินการแบบแบตช์เท่านั้น จากนั้นฉันก็ตระหนักว่าความสัมพันธ์ใดๆ ก็ตามอาจทำให้เกิดปัญหาคล้ายกันได้ สมมติว่าฟาร์มมีเจ้าของเป็นศูนย์หรือหนึ่งราย และเจ้าของสามารถมีฟาร์มเป็นศูนย์หรือหนึ่งรายได้

3. Single GET ใช้งานไม่ได้โดยการอัปเดตเป็นบันทึกที่เกี่ยวข้อง

GET /farms/123   # get info about Old MacDonald's Farm
PUT /farmers/987 # Old MacDonald sells his farm and buys another one
GET /farms/123

แคชรู้ได้อย่างไรว่าจะทำให้ GET เดียวใช้ไม่ได้เมื่อเห็นว่า PUT ผ่านไป

แม้ว่าคุณจะเปลี่ยนโมเดลให้มี RESTful มากขึ้น แต่การใช้โมเดลความสัมพันธ์ คุณจะพบปัญหาเดียวกัน:

GET    /farms/123           # get info about Old MacDonald's Farm
DELETE /farm_ownerships/456 # Old MacDonald sells his farm...
POST   /farm_ownerships     # and buys another one
GET    /farms/123

ใน #3 ทั้งสองเวอร์ชัน GET แรกควรส่งคืนสิ่งที่ต้องการ (ใน JSON):

farm: {
  id: 123,
  name: "Shady Acres",
  size: "60 acres",
  farmer_id: 987
}

และ GET อันที่สองควรส่งคืนดังนี้:

farm: {
  id: 123,
  name: "Shady Acres",
  size: "60 acres",
  farmer_id: null
}

แต่มันทำไม่ได้! ไม่แม้ว่าคุณจะใช้ ETags อย่างเหมาะสมก็ตาม คุณไม่สามารถคาดหวังให้เซิร์ฟเวอร์แคชตรวจสอบเนื้อหาสำหรับ ETags -- เนื้อหาอาจถูกเข้ารหัสได้ และคุณไม่สามารถคาดหวังให้เซิร์ฟเวอร์แจ้งแคชว่าบันทึกควรใช้งานไม่ได้ - แคชไม่ได้ลงทะเบียนตัวเองกับเซิร์ฟเวอร์

มีส่วนหัวที่ฉันหายไปบ้างไหม? สิ่งที่ระบุแคชควรทำ HEAD ก่อน GETs ใด ๆ สำหรับทรัพยากรบางอย่าง ฉันคิดว่าฉันสามารถอยู่กับคำขอซ้ำซ้อนสำหรับทุกทรัพยากรได้ หากฉันสามารถบอกแคชได้ว่าทรัพยากรใดมีแนวโน้มที่จะได้รับการอัปเดตบ่อยครั้ง

แล้วปัญหาของแคชตัวหนึ่งที่ได้รับ PUT และการรู้ว่าจะทำให้แคชนั้นใช้งานไม่ได้และอีกแคชหนึ่งไม่เห็นมันล่ะ


person James A. Rosen    schedule 11.01.2009    source แหล่งที่มา
comment
หลังจากเพิ่งสร้างเว็บแอปพลิเคชัน ajax ที่ตอบสนองอย่างรวดเร็ว ฉันค่อนข้างสนใจว่าคำถามนี้จะตอบอย่างไร +1 และติดดาว!   -  person Karl    schedule 11.01.2009
comment
บางทีสิ่งที่ฉันกำลังมองหาอาจเป็นส่วนหัวอื่นที่ไม่ถูกต้องซึ่งเซิร์ฟเวอร์สามารถเพิ่มเมื่อส่งคืนจาก PUT, POST หรือ DELETE อนิจจาดูเหมือนจะไม่มีอยู่จริง   -  person James A. Rosen    schedule 11.01.2009
comment
ในกรณีของ HTTPS พรอกซีจะไม่เห็นอะไรเลยนอกจากชื่อโฮสต์และพอร์ต พวกเขาไม่เห็นส่วนหัวหรือ pathInfo ดังนั้นจึงไม่มีปัญหา +++ Invalidates-Other เป็นสิ่งที่ฉันพยายามดิ้นรนเพื่อตั้งคำถามก่อนที่จะพบคำถามที่ยอดเยี่ยมของคุณ   -  person maaartinus    schedule 22.10.2016


คำตอบ (5)


เซิร์ฟเวอร์แคชควรจะทำให้เอนทิตีที่อ้างถึงโดย URI เป็นโมฆะเมื่อได้รับ PUT (แต่อย่างที่คุณสังเกตเห็น สิ่งนี้ไม่ได้ครอบคลุมทุกกรณี)

นอกเหนือจากนี้ คุณยังสามารถใช้ส่วนหัวการควบคุมแคชในการตอบกลับของคุณเพื่อจำกัดหรือป้องกันการแคช และลองประมวลผลส่วนหัวของคำขอที่ถามว่า URI ได้รับการแก้ไขนับตั้งแต่ดึงข้อมูลครั้งล่าสุดหรือไม่

นี่ยังคงเป็นปัญหาที่ซับซ้อนมากและในความเป็นจริงยังคงดำเนินการอยู่ (เช่น ดู http://www.ietf.org/internet-drafts/draft-ietf-httpbis-p6-cache-05.txt)

การแคชภายในพรอกซีใช้ไม่ได้จริงหากเนื้อหาถูกเข้ารหัส (อย่างน้อยก็ด้วย SSL) ดังนั้นจึงไม่น่าจะเป็นปัญหา (ยังคงอาจเป็นปัญหากับไคลเอนต์)

person frankodwyer    schedule 11.01.2009
comment
คำถามเดิมไม่ได้กล่าวถึงเซิร์ฟเวอร์แคช ฉันคิดว่ามันเกี่ยวกับแคชในเครื่องของเบราว์เซอร์ - person Karl; 11.01.2009
comment
ไม่ คำถามเดิมของฉันระบุว่า เซิร์ฟเวอร์แคชที่อยู่ระหว่างไคลเอนต์และเซิร์ฟเวอร์ Farms ทราบได้อย่างไรว่าแคชของ /farms/123 เป็นโมฆะเมื่อเห็น PUT ฉันหมายถึงทั้งแคชเซิร์ฟเวอร์และแคชในเครื่อง - person James A. Rosen; 11.01.2009
comment
Re: SSL: ดูความคิดเห็นของฉันเกี่ยวกับเนื้อหาที่เข้ารหัสผ่านช่องทางที่ไม่ได้เข้ารหัส - person James A. Rosen; 11.01.2009

โปรโตคอล HTTP รองรับประเภทคำขอที่เรียกว่า "If-Modified-Since" ซึ่งโดยพื้นฐานแล้วจะอนุญาตให้เซิร์ฟเวอร์แคชถามเว็บเซิร์ฟเวอร์ว่ารายการมีการเปลี่ยนแปลงหรือไม่ โปรโตคอล HTTP ยังรองรับส่วนหัว "การควบคุมแคช" ภายในการตอบสนองของเซิร์ฟเวอร์ HTTP ซึ่งจะบอกเซิร์ฟเวอร์แคชว่าจะทำอย่างไรกับเนื้อหา (เช่น อย่าแคชเนื้อหานี้ หรือถือว่าเนื้อหาจะหมดอายุใน 1 วัน เป็นต้น)

คุณยังพูดถึงการตอบกลับที่เข้ารหัสด้วย เซิร์ฟเวอร์แคช HTTP ไม่สามารถแคช SSL ได้ เนื่องจากจะต้องถอดรหัสหน้าต่างๆ ว่าเป็น "คนตรงกลาง" การทำเช่นนี้อาจเป็นเรื่องท้าทายทางเทคนิค (ถอดรหัสเพจ จัดเก็บ และเข้ารหัสอีกครั้งสำหรับไคลเอ็นต์) และยังจะเป็นการละเมิดความปลอดภัยของเพจซึ่งทำให้เกิดคำเตือน "ใบรับรองที่ไม่ถูกต้อง" ในฝั่งไคลเอ็นต์ ในทางเทคนิคแล้ว เป็นไปได้ที่เซิร์ฟเวอร์แคชจะดำเนินการดังกล่าว แต่จะทำให้เกิดปัญหามากกว่าที่จะแก้ไขได้ และเป็นความคิดที่ไม่ดี ฉันสงสัยว่าแคชเซิร์ฟเวอร์ใด ๆ ที่ทำสิ่งนี้จริง ๆ

person SoapBox    schedule 11.01.2009

น่าเสียดายที่การแคช HTTP ขึ้นอยู่กับ URI ที่แน่นอน และคุณไม่สามารถบรรลุพฤติกรรมที่สมเหตุสมผลในกรณีของคุณโดยไม่บังคับให้ไคลเอนต์ทำการตรวจสอบความถูกต้องของแคชอีกครั้ง

หากคุณมี:

GET /farm/123
POST /farm_update/123

คุณสามารถใช้ Content-Location header เพื่อระบุคำขอที่สองที่แก้ไขคำขอแรก AFAIK คุณไม่สามารถทำได้ด้วย URI หลายอัน และฉันไม่ได้ตรวจสอบว่าสิ่งนี้ใช้ได้กับไคลเอนต์ยอดนิยมหรือไม่

วิธีแก้ไขคือทำให้เพจหมดอายุอย่างรวดเร็วและจัดการ If-Modified-Since หรือ E-Tag ด้วยสถานะ 304 Not Modified

person Kornel    schedule 11.01.2009

คุณไม่สามารถแคชเนื้อหาไดนามิกได้ (โดยไม่มีข้อเสีย) เพราะ... มันเป็นไดนามิก

person Karsten    schedule 11.01.2009

ในคำตอบ: คำตอบของ SoapBox:

  1. ฉันคิดว่า If-Modified-Since เป็นสองขั้นตอน GET ที่ฉันแนะนำในตอนท้ายของคำถาม ดูเหมือนเป็นวิธีแก้ปัญหาที่ใช้ได้ในกรณีที่เนื้อหามีขนาดใหญ่ (เช่น ค่าใช้จ่ายในการเพิ่มจำนวนคำขอเป็นสองเท่า และค่าใช้จ่ายก็ถูกเอาชนะด้วยการไม่ส่งเนื้อหาซ้ำ นั่นไม่เป็นความจริงในตัวอย่าง Farms ของฉัน เนื่องจากข้อมูลของแต่ละฟาร์มสั้น)

  2. สมเหตุสมผลอย่างยิ่งที่จะสร้างระบบที่ส่งเนื้อหาที่เข้ารหัสผ่านช่องทางที่ไม่ได้เข้ารหัส (HTTP) ลองนึกภาพสถานการณ์ของสถาปัตยกรรมเชิงบริการที่การอัปเดตไม่บ่อยนักและ GETs เกิดขึ้น (ก) บ่อยครั้ง (ข) จำเป็นต้องอย่างมากอย่างรวดเร็ว และ (ค) จะต้องได้รับการเข้ารหัส คุณจะต้องสร้างเซิร์ฟเวอร์ที่ต้องใช้ส่วนหัว FROM (หรือเทียบเท่ากับคีย์ API ในพารามิเตอร์คำขอ) และส่งเนื้อหาเวอร์ชันที่เข้ารหัสแบบไม่สมมาตรกลับมาสำหรับผู้ขอ การเข้ารหัสแบบอสมมาตรนั้นช้า แต่ถ้าแคชอย่างเหมาะสม จะเอาชนะการจับมือ SSL แบบรวม (การเข้ารหัสแบบอสมมาตร) และการเข้ารหัสเนื้อหาแบบสมมาตร การเพิ่มแคชหน้าเซิร์ฟเวอร์นี้จะเร่งความเร็ว GETs ได้อย่างมาก

  3. เซิร์ฟเวอร์แคชสามารถแคช HTTPS GET ได้อย่างสมเหตุสมผลในช่วงเวลาสั้นๆ ธนาคารของฉันอาจใส่การควบคุมแคชประมาณ 5 นาทีในหน้าแรกของบัญชีและธุรกรรมล่าสุดของฉัน ฉันไม่น่าจะใช้เวลานานบนไซต์มากนัก ดังนั้นเซสชันจึงไม่นานนัก และฉันอาจจะต้องไปที่หน้าหลักของบัญชีหลายครั้งในขณะที่ฉันกำลังมองหาเช็คที่ฉันส่งไปเมื่อเร็วๆ นี้ ถึง SnorgTees

person Community    schedule 11.01.2009
comment
หาก-แก้ไข-เนื่องจากไม่เพิ่มจำนวนคำขอ - person Kornel; 11.01.2009
comment
ฉันค่อนข้างแน่ใจว่ามันเป็นเช่นนั้น หากแคชสามารถระบุได้ว่ารายการใดเป็นรายการปัจจุบัน ก็ไม่จำเป็นต้องส่งคำขอ If-Modified-Since คุณพูดถูกที่มันไม่ เพิ่มเป็นสองเท่า จำนวน ขึ้นอยู่กับอัตราส่วนการอ่านต่อการเขียน - person James A. Rosen; 11.01.2009
comment
If-Modified-Since ไม่ได้เพิ่มคำขอเป็นสองเท่า - เซิร์ฟเวอร์จะตอบกลับด้วยทรัพยากร (หากมีการเปลี่ยนแปลง) หรือการตอบกลับที่ไม่ได้แก้ไข ซึ่งไคลเอ็นต์ควรใช้เวอร์ชันที่พวกเขามีอยู่แล้ว - person Rowland Shaw; 11.01.2009
comment
คุณพูดถูก -- มันไม่ได้เพิ่มจำนวนเป็นสองเท่า แต่ HTTP §13.2.1 ¶1 บอกว่าการแคช HTTP ทำงานได้ดีที่สุดเมื่อแคชสามารถหลีกเลี่ยงการส่งคำขอไปยังเซิร์ฟเวอร์ต้นทางได้โดยสิ้นเชิง นั่นคือสิ่งที่ฉันตั้งเป้าไว้ - person James A. Rosen; 11.01.2009
comment
ขณะที่ฉันเจาะลึก ฉันพบว่าแคช HTTP ถูกสร้างขึ้นโดยมีแนวคิดในการส่งแคชกลับมาเพื่อตรวจสอบผ่าน If-Modified-Since ดูเหมือนว่าจะมีค่าใช้จ่ายมากมาย แต่ดูเหมือนว่าจะตอบปัญหาทั้งหมดของฉันได้ - person James A. Rosen; 11.01.2009
comment
เป็นไปไม่ได้ที่เซิร์ฟเวอร์แคชจะแคช https ที่ได้รับเนื่องจากช่องสัญญาณ SSL นั้นทึบแสงไปยังเซิร์ฟเวอร์ - จริงๆ แล้วไม่เห็นด้วยซ้ำว่าเป็น HTTP ปกติที่ทำด้วยวิธี CONNECT ซึ่งโดยพื้นฐานแล้วจะเจาะการเชื่อมต่อซ็อกเก็ตผ่านพร็อกซี - person frankodwyer; 11.01.2009
comment
(อันที่จริงฉันควรเพิ่มว่ามีพร็อกซีเชิงพาณิชย์บางตัวที่สามารถปลอมแปลง CA ที่น่าเกลียดเพื่อหลีกเลี่ยงคำเตือนใบรับรอง SSL แต่นี่เป็นวิธีแก้ปัญหาที่น่ากลัวมากและต้องการให้พร็อกซีได้รับการปฏิบัติเหมือนเป็น CA ที่เชื่อถือได้) - person frankodwyer; 11.01.2009
comment
@frankodwyer - ฉันเดาว่าฉันคิดเสมอว่าผู้รับมอบฉันทะสามารถเห็นส่วนหัวของการรับส่งข้อมูล SSL ฉันจะถือหมวกในมือ #3 ความคิดเห็นที่ดี - person James A. Rosen; 11.01.2009
comment
ความเห็นส่วนตัวของฉันคือเว็บแอปพลิเคชันธนาคารใดๆ ควร ไม่ แคชสิ่งใดๆ หากเกี่ยวข้องกับเรื่องเงินก็เป็นสิ่งสำคัญ และหากเป็นธนาคาร ก็ควรจัดหาฮาร์ดแวร์เพื่อรองรับคำขอที่ไม่ได้แคชทั้งหมด - person Andrei Rînea; 10.05.2009