Dùng Bộ nhớ đệm HTTP để ngăn các yêu cầu không cần thiết về mạng

Việc tìm nạp tài nguyên qua mạng vừa chậm vừa tốn kém:

  • Các phản hồi lớn yêu cầu nhiều lượt trả về giữa trình duyệt và máy chủ.
  • Trang của bạn sẽ không tải cho đến khi tất cả tài nguyên quan trọng của trang được tải xuống hoàn toàn.
  • Nếu một người đang truy cập vào trang web của bạn bằng gói dữ liệu di động có giới hạn, thì mọi yêu cầu mạng không cần thiết đều khiến họ lãng phí tiền.

Làm cách nào để tránh các yêu cầu mạng không cần thiết? Bộ nhớ đệm HTTP của trình duyệt là hàng rào bảo vệ đầu tiên của bạn. Đây không phải là phương pháp mạnh mẽ hoặc linh hoạt nhất và bạn có quyền kiểm soát hạn chế đối với thời gian hoạt động của các phản hồi được lưu vào bộ nhớ đệm, nhưng phương pháp này hiệu quả, được hỗ trợ trong tất cả trình duyệt và không yêu cầu nhiều thao tác.

Hướng dẫn này trình bày những kiến thức cơ bản về cách triển khai hiệu quả tính năng lưu vào bộ nhớ đệm HTTP.

Khả năng tương thích với trình duyệt

Trên thực tế, không có API nào có tên là Bộ nhớ đệm HTTP. Đây là tên chung cho một tập hợp các API nền tảng web. Các API đó được hỗ trợ trong tất cả trình duyệt:

Cache-Control

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

ETag

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

Last-Modified

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

Cách hoạt động của Bộ nhớ đệm HTTP

Trước tiên, tất cả các yêu cầu HTTP mà trình duyệt đưa ra đều được định tuyến đến bộ nhớ đệm của trình duyệt để kiểm tra xem có phản hồi hợp lệ được lưu vào bộ nhớ đệm có thể dùng để thực hiện yêu cầu hay không. Nếu có kết quả trùng khớp, phản hồi sẽ được đọc từ bộ nhớ đệm, giúp loại bỏ cả độ trễ mạng và chi phí dữ liệu phát sinh trong quá trình chuyển.

Hành vi của Bộ nhớ đệm HTTP được kiểm soát bằng cách kết hợp tiêu đề yêu cầutiêu đề phản hồi. Trong trường hợp lý tưởng, bạn sẽ có quyền kiểm soát cả mã cho ứng dụng web (sẽ xác định tiêu đề yêu cầu) và cấu hình của máy chủ web (sẽ xác định tiêu đề phản hồi).

Hãy tham khảo bài viết Lưu vào bộ nhớ đệm HTTP của MDN để biết thông tin tổng quan khái niệm chuyên sâu hơn.

Tiêu đề yêu cầu: sử dụng các tiêu đề mặc định (thường)

Có một số tiêu đề quan trọng cần đưa vào các yêu cầu gửi đi của ứng dụng web, nhưng trình duyệt hầu như luôn thay mặt bạn thiết lập các tiêu đề đó khi đưa ra yêu cầu. Các tiêu đề yêu cầu ảnh hưởng đến việc kiểm tra độ mới, chẳng hạn như If-None-MatchIf-Modified-Since xuất hiện dựa trên sự hiểu biết của trình duyệt về các giá trị hiện tại trong Bộ nhớ đệm HTTP.

Đây là tin vui – tức là bạn có thể tiếp tục đưa các thẻ như <img src="my-image.png"> vào HTML và trình duyệt sẽ tự động lưu vào bộ nhớ đệm HTTP cho bạn mà không cần thêm nỗ lực nào.

Tiêu đề phản hồi: định cấu hình máy chủ web

Phần quan trọng nhất trong quá trình thiết lập tính năng lưu vào bộ nhớ đệm HTTP là các tiêu đề mà máy chủ web của bạn thêm vào mỗi phản hồi gửi đi. Tất cả các tiêu đề sau đây đều ảnh hưởng đến hành vi lưu vào bộ nhớ đệm hiệu quả:

  • Cache-Control. Máy chủ có thể trả về một lệnh Cache-Control để chỉ định cách thức và thời lượng lưu trữ phản hồi riêng lẻ vào bộ nhớ đệm của trình duyệt và các bộ nhớ đệm trung gian khác.
  • ETag. Khi tìm thấy một phản hồi đã hết hạn trong bộ nhớ đệm, trình duyệt có thể gửi một mã thông báo nhỏ (thường là hàm băm của nội dung tệp) đến máy chủ để kiểm tra xem tệp có thay đổi hay không. Nếu máy chủ trả về cùng một mã thông báo, thì tệp đó cũng giống nhau và bạn không cần tải lại.
  • Last-Modified. Tiêu đề này phục vụ cùng một mục đích như ETag, nhưng sử dụng chiến lược dựa trên thời gian để xác định xem một tài nguyên có thay đổi hay không, trái ngược với chiến lược dựa trên nội dung của ETag.

Một số máy chủ web có hỗ trợ tích hợp để đặt các tiêu đề đó theo mặc định, trong khi một số khác lại loại bỏ hoàn toàn các tiêu đề trừ phi bạn định cấu hình rõ ràng các tiêu đề đó. Thông tin chi tiết cụ thể về cách định cấu hình tiêu đề sẽ khác nhau tuỳ thuộc vào máy chủ web mà bạn sử dụng. Bạn nên tham khảo tài liệu của máy chủ để biết thông tin chi tiết chính xác nhất.

Để giúp bạn tiết kiệm thời gian tìm kiếm, sau đây là hướng dẫn về cách định cấu hình một số máy chủ web phổ biến:

Việc bỏ qua tiêu đề phản hồi Cache-Control không vô hiệu hoá tính năng lưu vào bộ nhớ đệm HTTP! Thay vào đó, trình duyệt đoán hiệu quả loại hành vi lưu vào bộ nhớ đệm phù hợp nhất với một loại nội dung nhất định. Có thể bạn muốn có nhiều quyền kiểm soát hơn những gì mà tính năng này cung cấp, vì vậy, hãy dành thời gian định cấu hình tiêu đề phản hồi.

Bạn nên sử dụng giá trị tiêu đề phản hồi nào?

Có hai tình huống quan trọng mà bạn nên xem xét khi định cấu hình tiêu đề phản hồi của máy chủ web.

Lưu vào bộ nhớ đệm trong thời gian dài cho các URL có phiên bản

Giả sử máy chủ của bạn hướng dẫn trình duyệt lưu tệp CSS vào bộ nhớ đệm trong 1 năm (Cache-Control: max-age=31536000) nhưng nhà thiết kế của bạn vừa thực hiện một bản cập nhật khẩn cấp mà bạn cần triển khai ngay lập tức. Làm cách nào để bạn thông báo cho trình duyệt cập nhật bản sao "lỗi thời" của tệp trong bộ nhớ đệm? Bạn không thể, ít nhất là không thể thay đổi URL của tài nguyên.

Sau khi trình duyệt lưu phản hồi vào bộ nhớ đệm, phiên bản được lưu vào bộ nhớ đệm sẽ được sử dụng cho đến khi không còn mới, như được xác định bởi max-age hoặc expires, hoặc cho đến khi phiên bản đó bị xoá khỏi bộ nhớ đệm vì một số lý do khác – ví dụ: người dùng xoá bộ nhớ đệm của trình duyệt. Do đó, các người dùng khác nhau có thể sử dụng các phiên bản tệp khác nhau khi trang được tạo: những người dùng vừa tìm nạp tài nguyên sẽ sử dụng phiên bản mới, trong khi những người dùng đã lưu một bản sao trước đó (nhưng vẫn hợp lệ) vào bộ nhớ đệm sẽ sử dụng phiên bản cũ hơn của phản hồi.

Làm cách nào để bạn có được những ưu điểm tốt nhất của cả hai phương thức: lưu vào bộ nhớ đệm phía máy khách và cập nhật nhanh? Bạn thay đổi URL của tài nguyên và buộc người dùng tải phản hồi mới xuống mỗi khi nội dung của tài nguyên thay đổi. Thông thường, bạn thực hiện việc này bằng cách nhúng vân tay số của tệp hoặc số phiên bản vào tên tệp, ví dụ: style.x234dff.css.

Khi phản hồi các yêu cầu về URL chứa "vân tay số" hoặc thông tin phiên bản và nội dung không bao giờ thay đổi, hãy thêm Cache-Control: max-age=31536000 vào nội dung phản hồi.

Việc đặt giá trị này cho trình duyệt biết rằng khi cần tải cùng một URL bất cứ lúc nào trong vòng một năm tới (31.536.000 giây; giá trị tối đa được hỗ trợ), trình duyệt có thể sử dụng ngay giá trị trong Bộ nhớ đệm HTTP mà không cần phải tạo yêu cầu mạng đến máy chủ web của bạn. Thật tuyệt vời! Bạn đã ngay lập tức đạt được độ tin cậy và tốc độ nhờ tránh sử dụng mạng!

Các công cụ xây dựng như webpack có thể tự động hoá quy trình chỉ định vân tay băm cho URL thành phần của bạn.

Xác thực lại máy chủ cho URL không có phiên bản

Rất tiếc, không phải URL nào bạn tải cũng được tạo phiên bản. Có thể bạn không thể thêm bước tạo bản dựng trước khi triển khai ứng dụng web, vì vậy, bạn không thể thêm hàm băm vào URL tài sản. Và mọi ứng dụng web đều cần tệp HTML – những tệp đó (hầu như!) không bao giờ bao gồm thông tin phiên bản, vì không ai sẽ bận tâm đến việc sử dụng ứng dụng web của bạn nếu họ cần nhớ rằng URL cần truy cập là https://example.com/index.34def12.html. Vậy bạn có thể làm gì với những URL đó?

Đây là một tình huống mà bạn cần phải thừa nhận thất bại. Chỉ riêng việc lưu vào bộ nhớ đệm HTTP là chưa đủ để tránh hoàn toàn mạng. (Đừng lo – bạn sẽ sớm tìm hiểu về trình chạy dịch vụ. Đây là công cụ hỗ trợ cần thiết để giúp bạn giành lại chiến thắng.) Tuy nhiên, bạn có thể thực hiện một số bước để đảm bảo rằng các yêu cầu mạng diễn ra nhanh chóng và hiệu quả nhất có thể.

Các giá trị Cache-Control sau đây có thể giúp bạn tinh chỉnh vị trí và cách lưu các URL không có phiên bản vào bộ nhớ đệm:

  • no-cache. Thao tác này sẽ hướng dẫn trình duyệt phải xác thực lại với máy chủ mỗi khi sử dụng phiên bản URL đã lưu trong bộ nhớ đệm.
  • no-store. Thao tác này sẽ hướng dẫn trình duyệt và các bộ nhớ đệm trung gian khác (chẳng hạn như CDN) không bao giờ lưu trữ bất kỳ phiên bản nào của tệp.
  • private. Trình duyệt có thể lưu tệp vào bộ nhớ đệm nhưng bộ nhớ đệm trung gian thì không.
  • public. Mọi bộ nhớ đệm đều có thể lưu trữ phản hồi.

Hãy xem Phần phụ lục: Sơ đồ quy trình Cache-Control để hình dung quy trình quyết định(các) giá trị Cache-Control cần sử dụng. Cache-Control cũng có thể chấp nhận danh sách lệnh được phân tách bằng dấu phẩy. Xem Phần phụ lục: Ví dụ về Cache-Control.

Việc đặt ETag hoặc Last-Modified cũng có thể giúp ích. Như đã đề cập trong phần Tiêu đề phản hồi, ETagLast-Modified đều phục vụ cùng một mục đích: xác định xem trình duyệt có cần tải lại tệp đã hết hạn trong bộ nhớ đệm hay không. Bạn nên sử dụng ETag vì phương thức này chính xác hơn.

Giả sử đã 120 giây kể từ lần tìm nạp ban đầu và trình duyệt đã bắt đầu một yêu cầu mới cho cùng một tài nguyên. Trước tiên, trình duyệt sẽ kiểm tra Bộ nhớ đệm HTTP và tìm phản hồi trước đó. Rất tiếc, trình duyệt không thể sử dụng phản hồi trước đó vì phản hồi đó đã hết hạn. Tại thời điểm này, trình duyệt có thể gửi một yêu cầu mới và tìm nạp phản hồi đầy đủ mới. Tuy nhiên, việc này không hiệu quả vì nếu tài nguyên không thay đổi, thì không có lý do gì để tải cùng một thông tin đã có trong bộ nhớ đệm xuống!

Đó là vấn đề mà mã thông báo xác thực (như được chỉ định trong tiêu đề ETag) được thiết kế để giải quyết. Máy chủ sẽ tạo và trả về một mã thông báo tuỳ ý, thường là một hàm băm hoặc một số vân tay số khác của nội dung tệp. Trình duyệt không cần biết cách tạo vân tay số; trình duyệt chỉ cần gửi vân tay số đó đến máy chủ trong yêu cầu tiếp theo. Nếu vân tay vẫn giống nhau, thì tài nguyên đó chưa thay đổi và trình duyệt có thể bỏ qua quá trình tải xuống.

Việc đặt ETag hoặc Last-Modified giúp yêu cầu xác thực lại hiệu quả hơn nhiều bằng cách cho phép yêu cầu này kích hoạt các tiêu đề yêu cầu If-Modified-Since hoặc If-None-Match được đề cập trong phần Tiêu đề yêu cầu.

Khi thấy các tiêu đề yêu cầu đến đó, máy chủ web được định cấu hình đúng cách có thể xác nhận xem phiên bản tài nguyên mà trình duyệt đã có trong Bộ nhớ đệm HTTP có khớp với phiên bản mới nhất trên máy chủ web hay không. Nếu có kết quả trùng khớp, máy chủ có thể phản hồi bằng phản hồi HTTP 304 Not Modified, tương đương với "Này, hãy tiếp tục sử dụng những gì bạn đã có!" Có rất ít dữ liệu cần chuyển khi gửi loại phản hồi này, vì vậy, loại phản hồi này thường nhanh hơn nhiều so với việc phải gửi lại bản sao của tài nguyên thực tế đang được yêu cầu.

Hình ảnh trực quan về một ứng dụng khách yêu cầu tài nguyên và máy chủ phản hồi bằng tiêu đề 304.
Trình duyệt yêu cầu /file từ máy chủ và bao gồm tiêu đề If-None-Match để hướng dẫn máy chủ chỉ trả về tệp đầy đủ nếu ETag của tệp trên máy chủ không khớp với giá trị If-None-Match của trình duyệt. Trong trường hợp này, 2 giá trị đã khớp, vì vậy, máy chủ sẽ trả về một phản hồi 304 Not Modified kèm theo hướng dẫn về thời lượng lưu tệp vào bộ nhớ đệm (Cache-Control: max-age=120).

Tóm tắt

Bộ nhớ đệm HTTP là một cách hiệu quả để cải thiện hiệu suất tải vì bộ nhớ đệm này giúp giảm các yêu cầu mạng không cần thiết. Tính năng này được hỗ trợ trên tất cả trình duyệt và bạn không mất nhiều công sức để thiết lập.

Bạn có thể bắt đầu bằng các cấu hình Cache-Control sau:

  • Cache-Control: no-cache cho các tài nguyên cần được xác thực lại với máy chủ trước mỗi lần sử dụng.
  • Cache-Control: no-store cho các tài nguyên không bao giờ được lưu vào bộ nhớ đệm.
  • Cache-Control: max-age=31536000 cho tài nguyên có phiên bản.

Ngoài ra, tiêu đề ETag hoặc Last-Modified có thể giúp bạn xác thực lại các tài nguyên bộ nhớ đệm đã hết hạn một cách hiệu quả hơn.

Tìm hiểu thêm

Nếu bạn muốn tìm hiểu thêm về cách sử dụng tiêu đề Cache-Control, hãy xem hướng dẫn Các phương pháp hay nhất về việc lưu vào bộ nhớ đệm và các lỗi về thời gian tối đa của Jake Archibald.

Hãy xem bài viết Yêu bộ nhớ đệm để biết hướng dẫn về cách tối ưu hoá mức sử dụng bộ nhớ đệm cho khách truy cập cũ.

Phụ lục: Các mẹo khác

Nếu có thêm thời gian, bạn có thể tối ưu hoá việc sử dụng Bộ nhớ đệm HTTP theo các cách sau:

  • Sử dụng URL nhất quán. Nếu bạn phân phát cùng một nội dung trên nhiều URL, thì nội dung đó sẽ được tìm nạp và lưu trữ nhiều lần.
  • Giảm thiểu tỷ lệ rời bỏ. Nếu một phần của tài nguyên (chẳng hạn như tệp CSS) thường xuyên cập nhật, trong khi phần còn lại của tệp không cập nhật (chẳng hạn như mã thư viện), hãy cân nhắc tách mã thường xuyên cập nhật thành một tệp riêng biệt và sử dụng chiến lược lưu vào bộ nhớ đệm trong thời gian ngắn cho mã thường xuyên cập nhật và chiến lược lưu vào bộ nhớ đệm trong thời gian dài cho mã không thường xuyên thay đổi.
  • Hãy xem xét lệnh stale-while-revalidate mới nếu chính sách Cache-Control của bạn chấp nhận một mức độ lỗi thời nhất định.

Phụ lục: Sơ đồ quy trình Cache-Control

Lưu đồ
Quy trình quyết định đặt tiêu đề Cache-Control.

Phụ lục: Ví dụ về Cache-Control

Giá trị Cache-Control Giải thích
max-age=86400 Trình duyệt và bộ nhớ đệm trung gian có thể lưu phản hồi vào bộ nhớ đệm trong tối đa 1 ngày (60 giây x 60 phút x 24 giờ).
private, max-age=600 Trình duyệt có thể lưu phản hồi vào bộ nhớ đệm (nhưng không phải bộ nhớ đệm trung gian) trong tối đa 10 phút (60 giây x 10 phút).
public, max-age=31536000 Mọi bộ nhớ đệm đều có thể lưu trữ phản hồi trong 1 năm.
no-store Không được lưu phản hồi vào bộ nhớ đệm và phải tìm nạp toàn bộ trên mỗi yêu cầu.