2008-08-07 25 views
9

Tôi đang viết phương thức xử lý tài nguyên nơi tôi kiểm soát quyền truy cập vào các tệp khác nhau và tôi muốn có thể sử dụng bộ nhớ cache của trình duyệt. Câu hỏi của tôi là hai lần:Cách biết thời điểm gửi phản hồi 304 Không được sửa đổi

  1. Đó là những tiêu đề HTTP dứt khoát rằng tôi cần phải kiểm tra để biết chắc chắn liệu tôi có nên gửi một phản ứng 304, và những gì tôi tìm kiếm khi tôi kiểm tra xem chúng ?

  2. Ngoài ra, có bất kỳ tiêu đề nào mà tôi cần gửi khi ban đầu gửi tệp (như 'Sửa đổi lần cuối') làm phản hồi 200 không?

Một số mã psuedo có lẽ sẽ là câu trả lời hữu ích nhất.


Điều gì về tiêu đề bộ nhớ cache kiểm soát? Có thể các giá trị khác nhau có thể có ảnh hưởng đến những gì bạn gửi cho khách hàng (cụ thể là độ tuổi tối đa) hoặc chỉ nên nếu được sửa đổi kể từ khi được tuân theo?

+1

Tôi chỉ muốn thêm sau đó khi gửi phản hồi 304, bạn chỉ nên gửi tiêu đề chứ không phải nội dung. – GateKiller

Trả lời

8

Đây là cách tôi đã triển khai. Mã này đã hoạt động được hơn một năm và với nhiều trình duyệt, vì vậy tôi nghĩ nó khá đáng tin cậy. Điều này được dựa trên RFC 2616 và bằng cách quan sát những gì và thời điểm các trình duyệt khác nhau đang gửi.

Đây là giả:

 
server_etag = gen_etag_for_this_file(myfile) 
etag_from_browser = get_header("Etag") 

if etag_from_browser does not exist: 
    etag_from_browser = get_header("If-None-Match") 
if the browser has quoted the etag: 
    strip the quotes (e.g. "foo" --> foo) 

set server_etag into http header 

if etag_from_browser matches server_etag 
    send 304 return code to browser 

Dưới đây là một đoạn của logic máy chủ của tôi để xử lý này.

 
/* the client should set either Etag or If-None-Match */ 
/* some clients quote the parm, strip quotes if so */ 
mketag(etag, &sb); 

etagin = apr_table_get(r->headers_in, "Etag"); 
if (etagin == NULL) 
    etagin = apr_table_get(r->headers_in, "If-None-Match"); 
if (etag != NULL && etag[0] == '"') { 
    int sl; 
    sl = strlen(etag); 
    memmove(etag, etag+1, sl+1); 
    etag[sl-2] = 0; 
    logit(2,"etag=:%s:",etag); 
} 
... 
apr_table_add(r->headers_out, "ETag", etag); 
... 
if (etagin != NULL && strcmp(etagin, etag) == 0) { 
    /* if the etag matches, we return a 304 */ 
    rc = HTTP_NOT_MODIFIED; 
} 

Nếu bạn muốn trợ giúp về việc tạo một bài viết khác, tôi cũng sẽ tìm hiểu một số mã khác. HTH!

+0

Bạn có thực sự gặp những khách hàng gửi tiêu đề 'ETag' trong yêu cầu không? Nó chỉ được dùng để đáp ứng. Ngoài ra nó luôn luôn phải được trích dẫn theo spec. –

+0

Matt, máy khách gửi lại etag nó đã nhận trước đó, vì vậy máy chủ có thể quyết định xem HTTP_NOT_MODIFIED có phải là một phản hồi thích hợp hay không. Công việc chính của tôi vào thời điểm tôi làm điều này là với Firefox và Safari; cả hai đều sẽ bao gồm etag được lưu trữ nếu một yêu cầu trước đó cho tài nguyên đã cho đã đưa ra một etag cho máy khách. Xem dưới "Cách sử dụng điển hình" ở đây: http://en.wikipedia.org/wiki/HTTP_ETag –

+0

Khách hàng bao gồm (các) từ khóa của nó trong tiêu đề 'If-None-Match' /' If-Match'. Tôi chưa bao giờ thấy một UA gửi một tiêu đề 'ETag:" ... "' trong một yêu cầu, phải không? –

3

Bạn nên gửi 304 nếu khách hàng đã tuyên bố rõ ràng rằng nó có thể đã có trang trong bộ nhớ cache của nó. Đây được gọi là GET có điều kiện, bao gồm tiêu đề nếu được sửa đổi từ trong yêu cầu.

Về cơ bản, tiêu đề yêu cầu này chứa ngày mà khách hàng yêu cầu có bản sao được lưu trong bộ nhớ cache. Bạn nên kiểm tra xem nội dung đã thay đổi sau ngày này chưa và gửi 304 nếu chưa.

Xem http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 cho phần có liên quan trong RFC.

1

liên quan đến bộ nhớ cache-control:

Bạn không cần phải lo lắng về việc bộ nhớ cache kiểm soát khi phục vụ ra, khác với cách đặt nó vào một giá trị hợp lý. Về cơ bản nó nói với trình duyệt và các thực thể hạ lưu khác (chẳng hạn như một proxy) thời gian tối đa sẽ trôi qua trước khi hết thời gian cho bộ nhớ cache.

4

Phản hồi 304 không được sửa đổi có thể là kết quả của yêu cầu GET hoặc HEAD với tiêu đề If-Modified-Since ("IMS") hoặc If-Not-Match ("INM").

Để quyết định việc cần làm khi bạn nhận các tiêu đề này, hãy tưởng tượng rằng bạn đang xử lý yêu cầu GET mà không có các tiêu đề có điều kiện này. Xác định giá trị của các tiêu đề ETag và Last-Modified của bạn sẽ ở trong phản hồi đó và sử dụng chúng để đưa ra quyết định. Hy vọng rằng bạn đã xây dựng hệ thống của mình để xác định điều này ít tốn kém hơn là xây dựng phản hồi hoàn chỉnh.

Nếu có một INM và giá trị của tiêu đề đó cũng giống như giá trị mà bạn sẽ đặt trong ETag, sau đó trả lời với 304.

Nếu có một IMS và các giá trị ngày tháng trong phần đầu đó là muộn hơn số bạn sẽ đặt trong Sửa đổi lần cuối, sau đó trả lời bằng 304.

Khác, tiếp tục như thể yêu cầu không chứa các tiêu đề đó.

Để có cách tiếp cận ít tốn kém nhất cho phần 2 câu hỏi của bạn, hãy tìm ra tiêu đề (Hết hạn, ETag và Sửa đổi lần cuối) mà bạn có thể sản xuất một cách dễ dàng và chính xác trong ứng dụng web của mình.

Đối với các tài liệu đọc gợi ý:

http://www.w3.org/Protocols/rfc2616/rfc2616.html

http://www.mnot.net/cache_docs/

2

Chúng tôi cũng xử lý lưu trữ, nhưng bảo đảm, nguồn lực. Nếu bạn gửi/tạo tiêu đề ETAg (phần RFC 2616 13.3 khuyên bạn NÊN), thì khách hàng PHẢI sử dụng nó trong một yêu cầu có điều kiện (thường là trong tiêu đề If-None-Match - HTTP_IF_NONE_MATCH -). Nếu bạn gửi tiêu đề Last-Modified (một lần nữa bạn NÊN), thì bạn nên kiểm tra tiêu đề If-Modified-Since - HTTP_IF_MODIFIED_SINCE -. Nếu bạn gửi cả hai, sau đó khách hàng NÊN gửi cả hai, nhưng nó PHẢI gửi ETag. Cũng lưu ý rằng validtion chỉ được định nghĩa là kiểm tra các tiêu đề có điều kiện cho sự bình đẳng nghiêm ngặt so với các tiêu đề bạn sẽ gửi đi. Ngoài ra, chỉ có trình xác thực mạnh (chẳng hạn như ETag) sẽ được sử dụng cho các yêu cầu thay đổi (chỉ yêu cầu một phần tài nguyên).

Trên thực tế, kể từ khi các nguồn tài nguyên chúng ta đang bảo vệ là khá tĩnh, và một thời gian trễ thứ hai là chấp nhận được, chúng tôi đang làm như sau:

  1. Kiểm tra xem nếu người dùng được phép truy cập vào tài nguyên được yêu cầu

    Nếu không, chuyển hướng hoặc gửi phản hồi 4xx nếu thích hợp. Chúng tôi sẽ tạo ra 404 câu trả lời cho các yêu cầu trông giống như các nỗ lực tấn công hoặc cố gắng trắng trợn để thực hiện kết thúc bảo mật.

  2. So sánh If-Modified-Since đến cuối-Modified tiêu đề chúng tôi sẽ gửi cho (xem dưới đây) cho bình đẳng nghiêm ngặt

    Nếu chúng phù hợp, gửi một phản ứng và trang thoát chế biến 304 Not Modified

  3. Tạo một tiêu đề Last Modified bằng cách sử dụng thời gian sửa đổi của tài nguyên yêu cầu

    Tra cứu định dạng HTTP ngày trong RFC 2616

  4. Gửi nội dung tài nguyên tiêu đề và nội dung cùng với một Loại nội dung phù hợp

Chúng tôi quyết định tránh tiêu đề ETag vì nó quá mức cần thiết cho mục đích của chúng tôi. Tôi cho rằng chúng ta cũng có thể sử dụng dấu ngày tháng làm ETag. Nếu chúng ta chuyển sang một hệ thống ETag thực sự, chúng ta có thể lưu trữ các băm tính toán cho các tài nguyên và sử dụng chúng như các ETags.

Nếu tài nguyên của bạn được tạo động, từ nội dung cơ sở dữ liệu, thì ETags có thể tốt hơn cho nhu cầu của bạn, vì chúng chỉ là văn bản được điền khi bạn thấy phù hợp.

Các vấn đề liên quan