हर दस्तावेज़ के साथ स्थिर वैलिडेटर भेजकर, क्लाइंट के सहेजे हुए वैलिडेटर जाँचकर और मौजूदा दस्तावेज़ या बिना बॉडी वाला 304 Not Modified लौटाकर conditional GET लागू करें। यह Mac ट्यूटोरियल एक कृत्रिम टेक्स्ट पेज के साथ प्रक्रिया दिखाता है।
लक्ष्य यह है कि किसी सार्वजनिक दस्तावेज़ के बार-बार किए गए अनुरोधों में उसकी सामग्री केवल ज़रूरत पड़ने पर ही स्थानांतरित हो। आप एक छोटा स्थानीय Python सर्वर चलाएँगे, Terminal से उसका परीक्षण करेंगे और दस्तावेज़ के अपडेट का अनुकरण करेंगे। उदाहरण स्थानीय ही रहेगा; इसे प्रकाशित करना एक अलग काम है।
सर्वर 200 और 304 में से कैसे चुने?
पहले अनुरोध पर 200 OK, दस्तावेज़ की बॉडी और उसके वैलिडेटर मिलते हैं। बाद के conditional अनुरोधों में सहेजे हुए वैलिडेटर वापस भेजे जाते हैं। यदि दस्तावेज़ में कोई बदलाव नहीं हुआ है, तो सर्वर 304 Not Modified लौटाता है, जिससे क्लाइंट अपनी संग्रहीत बॉडी का फिर से उपयोग कर सकता है। बदली हुई सामग्री को नया 200 प्रतिसाद मिलता है। HTTP conditional requests।
किसी मौजूदा दस्तावेज़ के लिए, जिस पर अन्यथा 200 लौटता, यह निर्णय क्रम अपनाएँ। If-None-Match को If-Modified-Since पर प्राथमिकता मिलती है; ये दो स्वतंत्र जाँचें नहीं हैं। RFC 9110, conditional request fields।
| अनुरोध की शर्त | प्रतिसाद |
|---|---|
| कोई conditional header नहीं | दस्तावेज़ के साथ 200 |
If-None-Match मौजूदा टैग से मेल खाता है |
बिना बॉडी के 304 |
If-None-Match मौजूद है, लेकिन मेल नहीं खाता |
200, भले ही दी गई तारीख बदलाव न होने का संकेत दे |
केवल वैध If-Modified-Since दिया गया है और दस्तावेज़ उससे नया नहीं है |
बिना बॉडी के 304 |
केवल वैध If-Modified-Since दिया गया है और दस्तावेज़ उससे नया है |
दस्तावेज़ के साथ 200 |
दस्तावेज़ चुनने और उसका सामान्य प्रतिसाद तय करने के बाद इन शर्तों का मूल्यांकन करें। यदि दस्तावेज़ मौजूद नहीं है, तो संसाधन अनुपलब्ध होने का सामान्य प्रतिसाद ही मिलना चाहिए। 304 में सामग्री या trailers नहीं हो सकते। उसमें लागू cache metadata शामिल होना चाहिए, जैसे Date, ETag, Vary, Cache-Control, Expires और Content-Location fields, जो उसके 200 प्रतिसाद के साथ भी आते। RFC 9110, precondition evaluation और 304 requirements।
ऐसे वैलिडेटर चुनें जो प्रकाशित दस्तावेज़ का वर्णन करें
ETag एक उद्धरण-चिह्नों में दिया गया संस्करण पहचानकर्ता है, जैसे "doc-v1"। इसे बनाने की विधि कार्यान्वयन पर निर्भर करती है: संशोधन पहचानकर्ता या सामग्री का हैश, दोनों काम कर सकते हैं। एक ही representation के लिए इसे स्थिर रखें और representation बदलने पर इसे बदलें। इस उदाहरण में दो स्पष्ट संशोधन हैं, जिनकी सामग्री तय है। ETag header।
एक strong tag किसी विशिष्ट representation की पहचान करता है; weak tag में W/ उपसर्ग होता है और वह ऐसी अर्थ की दृष्टि से समान सामग्री का वर्णन कर सकता है जिसके बाइट अलग हों। If-None-Match के साथ conditional GET तुलना में weak comparison का उपयोग होता है, इसलिए W/"doc-v1", "doc-v1" से मेल खाता है। अनुरोधों में टैगों की सूची या अकेला wildcard * भी हो सकता है। RFC 9110, If-None-Match।
Last-Modified बताता है कि दस्तावेज़ में बदलाव कब हुआ। हर अनुरोध के समय के बजाय, संबंधित दस्तावेज़ घटकों को ध्यान में रखते हुए लगातार एक ही तरीके से निर्धारित किया गया संशोधन समय इस्तेमाल करें। यह प्रतिसाद के Date से बाद का नहीं होना चाहिए। RFC 9110, Last-Modified generation।
नमूने में दो कृत्रिम संशोधनों को जानबूझकर उदाहरण के लिए प्रकाशन समय दिए गए हैं: 1 और 2 जनवरी 2024 को GMT दोपहर। ये तारीखें fixture data हैं। वास्तविक प्रकाशन प्रक्रिया में अनुरक्षित प्रकाशन metadata का उपयोग करें। सामग्री के अंतर का पता लगाने में Last-Modified, ETag से कम सटीक है और एक उपयोगी fallback देता है। Last-Modified header।
Cache policy अलग से चुनें
वैलिडेटर बताते हैं कि संग्रहीत प्रति अब भी मेल खाती है या नहीं। Freshness policy तय करती है कि cache को कब पूछना होगा। इस ट्यूटोरियल में Cache-Control: no-cache भेजा जाता है, जो संग्रहण की अनुमति देता है, लेकिन दोबारा उपयोग से पहले सफल validation आवश्यक बनाता है। इससे बार-बार किए गए अनुरोधों का व्यवहार आसानी से देखा जा सकता है। no-store संग्रहण को प्रतिबंधित करता है, जबकि max-age प्रतिसाद के fresh रहने तक दोबारा उपयोग की अनुमति देता है। RFC 9111, response cache directives।
ऐसे सार्वजनिक दस्तावेज़ के लिए, जिसमें अपडेट दिखने में थोड़ी देरी स्वीकार्य हो, max-age=60 जैसी policy उपयुक्त हो सकती है। यह केवल एक उदाहरणात्मक संपादकीय विकल्प है: दस्तावेज़ की अपडेट संबंधी ज़रूरतों के अनुसार अवधि चुनें। fresh cached response को सर्वर से संपर्क किए बिना दोबारा इस्तेमाल किया जा सकता है, इसलिए हर बार आने पर 304 मिलना ज़रूरी नहीं है। RFC 9111, freshness।
अपने Mac पर पूरा स्थानीय उदाहरण चलाएँ
Terminal खोलें और निम्न कमांड से ज़रूरी शर्तें जाँचें। Python 3.9 या नया संस्करण इस्तेमाल करें, क्योंकि प्रोग्राम str.removeprefix का उपयोग करता है। यदि python3 उपलब्ध नहीं है, तो आगे बढ़ने से पहले Python 3 इंस्टॉल करें। किसी तीसरे पक्ष के Python पैकेज की ज़रूरत नहीं है।
python3 --version
curl --version
एक नए कार्य फ़ोल्डर में, नीचे दिए गए पूरे प्रोग्राम को plain-text code editor से server.py नाम की फ़ाइल में सहेजें। यह केवल /page.txt को सर्व करता है, GET और HEAD लागू करता है और command-line argument से दस्तावेज़ का संशोधन चुनता है। Python का BaseHTTPRequestHandler अनुरोधों को संबंधित methods तक भेजता है और प्रतिसाद लिखने के helper देता है। Python HTTP server documentation।
import argparse
import re
from datetime import datetime, timezone
from email.utils import format_datetime, parsedate_to_datetime
from http.server import BaseHTTPRequestHandler, HTTPServer
parser = argparse.ArgumentParser()
parser.add_argument("version", type=int, choices=(1, 2))
args = parser.parse_args()
BODY = {
1: b"Paper Shapes\nA circle and a square.\n",
2: b"Paper Shapes\nA circle, a square, and a triangle.\n",
}[args.version]
ETAG = '"doc-v%d"' % args.version
MODIFIED = datetime(2024, 1, args.version, 12, tzinfo=timezone.utc)
LAST_MODIFIED = format_datetime(MODIFIED, usegmt=True)
TOKEN = r'(?:W/)?"[\x21\x23-\x7e\x80-\xff]*"'
TAG_LIST = re.compile(rf'[ \t]*(?:{TOKEN})?(?:[ \t]*,[ \t]*(?:{TOKEN})?)*[ \t]*')
def tag_matches(value):
if value.strip() == "*":
return True
if not TAG_LIST.fullmatch(value):
return False
return any(tag.removeprefix("W/") == ETAG
for tag in re.findall(TOKEN, value))
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.serve_document()
def do_HEAD(self):
self.serve_document()
def serve_document(self):
if self.path != "/page.txt":
self.send_error(404)
return
not_modified = False
tags = self.headers.get_all("If-None-Match")
if tags is not None:
not_modified = tag_matches(",".join(tags))
else:
dates = self.headers.get_all("If-Modified-Since", [])
if len(dates) == 1:
try:
since = parsedate_to_datetime(dates[0])
if since.tzinfo is None:
since = since.replace(tzinfo=timezone.utc)
not_modified = MODIFIED <= since
except (TypeError, ValueError, OverflowError):
pass
self.send_response(304 if not_modified else 200)
self.send_header("ETag", ETAG)
self.send_header("Cache-Control", "no-cache")
if not not_modified:
self.send_header("Last-Modified", LAST_MODIFIED)
self.send_header("Content-Type", "text/plain; charset=utf-8")
self.send_header("Content-Length", str(len(BODY)))
self.end_headers()
if not not_modified and self.command == "GET":
self.wfile.write(BODY)
if __name__ == "__main__":
HTTPServer(("127.0.0.1", 8000), Handler).serve_forever()
यह दो बताए गए वैलिडेटर का स्थानीय प्रदर्शन है, पूरा HTTP serving stack नहीं। तारीख बदलने के लिए यह Python के permissive email-date parser का उपयोग करता है; तैनात किए गए कार्यान्वयन में HTTP-विशिष्ट date validation और conditional-request handling का उपयोग होना चाहिए। Python उस parser द्वारा स्वीकार किए जाने वाले inputs और exceptions का दस्तावेज़ देता है। Python email date utilities।
Terminal में server.py वाले फ़ोल्डर में जाएँ और revision 1 शुरू करें। वह विंडो चालू रहने दें। यदि port 8000 पहले से इस्तेमाल हो रहा है, तो प्रोग्राम में कोई दूसरा उपलब्ध port चुनें और हर test URL में वही port इस्तेमाल करें।
python3 server.py 1
अपरिवर्तित सामग्री, बदली हुई सामग्री और प्राथमिकता जाँचें
एक और Terminal विंडो खोलें। नीचे दिए गए अनुरोध प्रतिसाद के headers और लौटाई गई किसी भी बॉडी को दिखाते हैं। -i विकल्प headers शामिल करता है, -H अनुरोध header देता है और --max-time हर transfer की अधिकतम अवधि तय करता है। curl manual।
शुरुआती प्रतिसाद प्राप्त करें
curl --max-time 5 -sS -i http://127.0.0.1:8000/page.txt
200 OK, कृत्रिम पेज का टेक्स्ट, ETag: "doc-v1" और Last-Modified: Mon, 01 Jan 2024 12:00:00 GMT मिलने की अपेक्षा करें। इस प्रक्रिया को किसी अन्य दस्तावेज़ पर लागू करते समय वास्तव में लौटाए गए मान दर्ज करें; वैलिडेटर उसी विशिष्ट प्रतिसाद के होते हैं।
हर वैलिडेटर के साथ फिर से validation करें
curl --max-time 5 -sS -i \
-H 'If-None-Match: "doc-v1"' \
http://127.0.0.1:8000/page.txt
curl --max-time 5 -sS -i \
-H 'If-Modified-Since: Mon, 01 Jan 2024 12:00:00 GMT' \
http://127.0.0.1:8000/page.txt
दोनों अनुरोधों को पेज का टेक्स्ट दिए बिना 304 Not Modified लौटाना चाहिए। प्रतिसाद में ETag और Cache-Control बने रहते हैं; Python का response helper Date जोड़ता है। पहले अनुरोध को W/"doc-v1" के साथ दोहराने पर भी 304 लौटना चाहिए। नमूना टैगों को बिना सोचे-समझे commas पर बाँटने के बजाय quoted tags को parse करता है, क्योंकि किसी टैग में comma हो सकता है।
साबित करें कि ETag को प्राथमिकता मिलती है
curl --max-time 5 -sS -i \
-H 'If-None-Match: "older-revision"' \
-H 'If-Modified-Since: Wed, 03 Jan 2024 12:00:00 GMT' \
http://127.0.0.1:8000/page.txt
दस्तावेज़ के साथ 200 OK मिलने की अपेक्षा करें। टैग मेल नहीं खाता, इसलिए बाद की तारीख से 304 नहीं मिलना चाहिए। यह जानबूझकर परस्पर विरोधी अनुरोध उस कार्यान्वयन को पकड़ता है जिसमें गलती से दोनों जाँचें मिला दी गई हों।
अगला संशोधन प्रकाशित करने का अनुकरण करें
सर्वर वाली विंडो में Control-C दबाएँ, फिर revision 2 शुरू करें। अनुरोध URL वही रखें।
python3 server.py 2
revision 1 के वैलिडेटर वाले पहले के दोनों revalidation अनुरोध दोहराएँ। अब दोनों को 200, त्रिकोण का उल्लेख करने वाला अपडेटेड वाक्य, ETag: "doc-v2" और 2 जनवरी की संशोधन तारीख मिलनी चाहिए। If-None-Match: "doc-v2" वाले अनुरोध को दोहराने पर 304 लौटना चाहिए।
इन नतीजों से स्वीकृति जाँच का क्रम बनता है: शुरुआती डाउनलोड, अपरिवर्तित सामग्री का validation, परस्पर विरोधी वैलिडेटर, बदला हुआ दस्तावेज़, फिर नए संशोधन का validation। नमूने को दोनों संशोधनों पर 24 स्थानीय जाँचों के साथ चलाया गया, जिनमें weak tags, tag lists, wildcard matching, HEAD और अनुपस्थित paths शामिल थे।
ब्राउज़र और Google के अनुरोध अलग क्यों दिख सकते हैं
ब्राउज़र आम तौर पर अपने cache के ज़रिए HTTP वैलिडेटर प्रबंधित करते हैं। WHATWG Fetch algorithm revalidation करते समय सहेजे हुए वैलिडेटर जोड़ता है और सफल 304 के बाद संग्रहीत प्रतिसाद के headers अपडेट करके वही संग्रहीत प्रतिसाद लौटाता है। इसलिए application JavaScript को उपयोग योग्य 200 प्रतिसाद और दस्तावेज़ की बॉडी मिल सकती है, भले ही network revalidation में 304 मिला हो। Fetch Standard, HTTP-network-or-cache fetch।
सर्वर के व्यवहार की जाँच करते समय, ऊपर दिए गए स्पष्ट curl अनुरोधों से शुरू करें। ब्राउज़र JavaScript में conditional headers खुद देने से परीक्षण बदल जाता है: ऐसे headers वाले default-cache अनुरोध पर Fetch, no-store पर स्विच कर जाता है। सामान्य browser revalidation जाँचने के लिए ब्राउज़र को अपना cache प्रबंधित करने दें। Fetch Standard, request cache mode।
Google का crawling infrastructure वैलिडेटर के दोनों जोड़ों का समर्थन करता है और ETags की सिफारिश करता है, क्योंकि उनसे तारीख के फ़ॉर्मैट की समस्याएँ नहीं होतीं। इसके दस्तावेज़ के अनुसार, उस infrastructure द्वारा अन्य HTTP caching directives समर्थित नहीं हैं। Google द्वारा दोबारा crawl करने की अपेक्षाओं से अलग अपनी browser cache policy चुनें। Overview of Google crawlers and fetchers।
Google हर crawl प्रयास पर conditional headers नहीं भेजता। उसके Search दस्तावेज़ के अनुसार, 304 पहले crawl की गई सामग्री के दोबारा उपयोग की अनुमति देता है, जबकि नई सामग्री को अपडेटेड बॉडी के साथ 200 मिल सकता है। सामान्य unconditional अनुरोधों को काम करते रहने दें; बिना वैलिडेटर वाला crawler अनुरोध इस बात का प्रमाण नहीं है कि आपका कार्यान्वयन विफल हुआ। Troubleshoot Google Search crawling errors।
इस तरीके को किसी प्रकाशित दस्तावेज़ पर लागू करने से पहले, उसके वास्तविक serving URL पर स्वीकृति जाँच का क्रम दोहराएँ। जाँचें कि अपरिवर्तित संशोधनों के वैलिडेटर बने रहते हैं, संपादन होने पर वे अपडेट होते हैं और 304 में दस्तावेज़ की कोई बॉडी नहीं होती। इससे दस्तावेज़ का सही पुनः उपयोग होता है और बदली हुई सामग्री फिर भी प्राप्त की जा सकती है।
स्रोत
- RFC 9110: HTTP Semantics — IETF / RFC Editor।
- RFC 9111: HTTP Caching — IETF / RFC Editor।
- Fetch Standard — WHATWG।
- HTTP conditional requests — MDN Web Docs।
- ETag header — MDN Web Docs।
- Last-Modified header — MDN Web Docs।
- http.server — HTTP servers — Python Software Foundation।
- email.utils: Miscellaneous utilities — Python Software Foundation।
- curl — How To Use — curl project।
- Overview of Google crawlers and fetchers (user agents) — Google।
- Troubleshoot Google Search crawling errors — Google Search Central।