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 các tài nguyên qua mạng vừa chậm vừa tốn kém:

  • Phản hồi lớn yêu cầu nhiều vòng tròn 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 người dùng trên trang web của bạn có gói dữ liệu di động hạn chế, thì mọi yêu cầu mạng không cần thiết đều là lãng phí tiền bạc.

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à tuyến phòng vệ đầu tiên. Đây không nhất thiết 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ế trong thời gian tồn tại của các phản hồi được lưu vào bộ nhớ đệm, nhưng cách này hiệu quả, được hỗ trợ trong mọi trình duyệt và không đòi hỏi nhiều việc.

Hướng dẫn này trình bày các thông tin cơ bản về việc triển khai bộ nhớ đệm HTTP hiệu quả.

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

Bộ nhớ đệm HTTP là tên chung của tập hợp các API nền tảng web được hỗ trợ trong mọi trình duyệt:

Cache-Control

Hỗ trợ trình duyệt

  • Đúng
  • 12
  • Đúng
  • Đúng

Nguồn

ETag

Hỗ trợ trình duyệt

  • Đúng
  • 12
  • Đúng
  • Đúng

Nguồn

Last-Modified

Hỗ trợ trình duyệt

  • Đúng
  • 12
  • Đúng
  • Đúng

Nguồn

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 thực hiện đều được chuyển đến bộ nhớ đệm của trình duyệt để kiểm tra xem có phản hồi nào hợp lệ vào bộ nhớ đệm có thể dùng để thực hiện yêu cầu đó hay không. Nếu trùng khớp, phản hồi sẽ được đọc từ bộ nhớ đệm, qua đó loại bỏ cả độ trễ mạng và chi phí dữ liệu của quá trình chuyển.

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

Hãy tham khảo bài viết về Bộ nhớ đệm HTTP của MDN để biết thông tin tổng quan chi tiết hơn về khái niệm.

Tiêu đề yêu cầu: giữ nguyên tiêu đề mặc định (thường)

Có một số tiêu đề quan trọng cần được đư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 đặt các tiêu đề đó khi đưa ra yêu cầu. Các tiêu đề của 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 sẽ xuất hiện dựa trên hiểu biết của trình duyệt về các giá trị hiện tại trong Bộ nhớ đệm HTTP.

Tin vui: bạn có thể tiếp tục đưa các thẻ như <img src="my-image.png"> vào HTML của mình và trình duyệt sẽ tự động xử lý việc lưu vào bộ nhớ đệm HTTP mà không mất thêm công sức.

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

Phần quan trọng nhất trong quá trình thiết lập bộ nhớ đệm HTTP là tiêu đề mà máy chủ web của bạn thêm vào mỗi phản hồi gửi đi. Các tiêu đề sau đây đều ảnh hưởng đến hoạt động 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à khoảng thời gian mà trình duyệt và các bộ nhớ đệm trung gian khác cần lưu từng phản hồi vào bộ nhớ đệm.
ETag.
Khi tìm thấy một phản hồi đã hết hạn lưu vào 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 đã thay đổi hay chưa. Nếu máy chủ trả về cùng một mã thông báo, thì tệp sẽ giữ nguyên và bạn không cần tải xuống lại.
Last-Modified
Tiêu đề này có mục đích tương tự như ETag, nhưng sử dụng chiến lược dựa trên thời gian để xác định xem tài nguyên đã thay đổi hay chưa, 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ó tính năng hỗ trợ cài đặt sẵn các tiêu đề đó theo mặc định. Một số khác thì bỏ hoàn toàn tiêu đề, trừ phi bạn định cấu hình các tiêu đề một cách rõ ràng. Thông tin chi tiết cụ thể về cách định cấu hình tiêu đề sẽ khác nhau đáng kể 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ủ đó để có được thông tin chính xác nhất.

Để tiết kiệm công sức tìm kiếm, dưới đây là hướng dẫn cách định cấu hình một số máy chủ web phổ biến:

Việc bỏ đi tiêu đề phản hồi Cache-Control sẽ không tắt tính năng lưu vào bộ nhớ đệm của HTTP! Thay vào đó, các trình duyệt sẽ đo lường một cách hiệu quả loại hành vi lưu vào bộ nhớ đệm nào phù hợp nhất đối 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ì mang lại, vì vậy, bạn sẽ cần 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ó 2 trường hợp quan trọng mà bạn nên đề cập 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 tồn tại trong thời gian dài cho các URL được tạo phiên bản

Cách URL được tạo phiên bản có thể giúp ích cho chiến lược lưu vào bộ nhớ đệm của bạn
URL đã tạo phiên bản là một phương pháp hay vì chúng giúp vô hiệu hoá các phản hồi đã lưu vào bộ nhớ đệm một cách dễ dàng hơn.

Giả sử máy chủ của bạn hướng dẫn trình duyệt lưu một 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 và 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ể làm 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 đã lưu vào bộ nhớ đệm sẽ được sử dụng cho đến khi không còn mới, như do max-age hoặc expires xác định, hoặc cho đến khi bị loại khỏi bộ nhớ đệm vì một số lý do khác, chẳng hạn như người dùng xoá bộ nhớ đệm của trình duyệt. Kết quả là, có những người dùng khác nhau có thể sẽ tải các phiên bản khác nhau của tệp 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, nhưng những người dùng đã lưu vào bộ nhớ đệm một bản sao cũ (nhưng vẫn hợp lệ) lại sử dụng một phiên bản cũ.

Để nhận được cả chức năng lưu vào bộ nhớ đệm phía máy khách và cập nhật nhanh, bạn có thể 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 của tệp vào tên tệp, ví dụ như style.x234dff.css.

Khi phản hồi các yêu cầu về URL chứa "vân tay" 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 phản hồi của bạn.

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 năm tiếp theo (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 gửi yêu cầu mạng tới máy chủ web của bạn. Thật tuyệt! Bạn sẽ ngay lập tức đạt được độ tin cậy và tốc độ nhờ tính năng tránh mạng!

Các công cụ tạo 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 chưa được tạo phiên bản

Rất tiếc, không phải tất cả URL bạn tải đều được tạo phiên bản. Có lẽ bạn không đưa được 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 nội dung của mình. Và mọi ứng dụng web đều cần tệp HTML, hầu như không bao giờ bao gồm thông tin phiên bản, vì không ai bận tâm 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 đó?

Chỉ riêng việc lưu vào bộ nhớ đệm của HTTP là không đủ hiệu quả để tránh hoàn toàn mạng. (Đừng lo – bạn sẽ sớm tìm hiểu về service worker, cung cấp thêm khả năng hỗ trợ.) Tuy nhiên, có một vài bước bạn có thể thực hiện để đảm bảo rằng các yêu cầu mạng sẽ 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 thức lưu các URL chưa được tạo phiên bản vào bộ nhớ đệm:

  • no-cache cho trình duyệt biết rằng phải luôn xác thực lại với máy chủ trước khi sử dụng phiên bản URL đã lưu vào bộ nhớ đệm.
  • no-store yêu cầu trình duyệt và các bộ nhớ đệm trung gian khác (như CDN) không bao giờ lưu trữ bất kỳ phiên bản nào của tệp.
  • private: Các 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.

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

Đặ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 đã lưu vào bộ nhớ đệm đã hết hạn hay không. Bạn nên dùng ETag vì cách này chính xác hơn.

Ví dụ về ETag

Giả sử đã 120 giây kể từ lần tìm nạp đầu tiên và trình duyệt đã khởi tạo 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 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, cách 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 lại thông tin đã có trong bộ nhớ đệm.
Đây là vấn đề mà mã thông báo xác thực 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 vân tay được tạo ra như thế nào. SDK chỉ cần gửi bản ghi này đến máy chủ trong yêu cầu tiếp theo. Nếu vân tay số vẫn giữ nguyên, thì tài nguyên đó không 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 kích hoạt những tiêu đề của yêu cầu If-Modified-Since hoặc If-None-Match được đề cập trong Tiêu đề của yêu cầu.

Khi một máy chủ web được định cấu hình đúng cách nhìn thấy các tiêu đề của yêu cầu đến, máy chủ có thể xác nhận xem phiên bản của 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 "Ok, 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, việc này thường nhanh hơn nhiều so với việc thực sự gửi lại bản sao tài nguyên thực tế đang được yêu cầu.

Sơ đồ về ứng dụng 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, các giá trị khớp với nhau nên máy chủ sẽ trả về phản hồi 304 Not Modified kèm theo hướng dẫn về thời gian 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ảm các yêu cầu mạng không cần thiết. Tính năng này được hỗ trợ trong tất cả các trình duyệt và bạn không mất quá nhiều công sức để thiết lập.

Các cấu hình Cache-Control sau đây là một khởi đầu tốt:

  • 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 các tài nguyên được tạo phiên bản.

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 sâu hơn những kiến thức cơ bản 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 để lưu vào bộ nhớ đệm và hướng dẫn về Gotchas tuổi tối đa của Jake Archibald.

Hãy xem bài viết Yêu thích 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ể tham khảo thêm các cách sau đây để tối ưu hoá việc sử dụng Bộ nhớ đệm HTTP:

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

Phụ lục: lưu đồ quy trình Cache-Control

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

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

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