navigator.sendBeacon बनाम fetch keepalive: नेविगेशन को रोके बिना भरोसेमंद एनालिटिक्स डिलीवरी
नेविगेशन को रोके बिना पेज अनलोड से बचकर एनालिटिक्स पेलोड कैसे भेजें — और कुकी-रहित कलेक्शन के लिए sendBeacon और fetch keepalive के बीच का चुनाव क्यों मायने रखता है।
जब तक पेज सक्रिय (alive) है, तब तक पेज व्यू या इवेंट रिकॉर्ड करना आसान है। असली चुनौती यह है कि जब यूज़र कहीं और नेविगेट करे, टैब बंद करे, या मोबाइल पर ऐप को बैकग्राउंड में भेजे, ठीक उसी क्षण उस आखिरी पेलोड को डिलीवर किया जाए। अगर यह गलत हुआ, तो या तो डेटा खो जाता है, या इससे भी बुरा, यूज़र ने जिस नेविगेशन के लिए कहा था, वही धीमा हो जाता है। यह पोस्ट दो व्यावहारिक विकल्पों की तुलना करता है — navigator.sendBeacon() और keepalive: true के साथ fetch() — और बताता है कि Monoid का ट्रैकर असल में किसका उपयोग करता है, और क्यों, वह भी बिना किसी कुकी, स्टोरेज या फिंगरप्रिंटिंग के।
अनलोड एक विशेष मामला क्यों है
जब कोई दस्तावेज़ (document) अनलोड होना शुरू करता है, तब ब्राउज़र पहले से ही बंद होने की प्रक्रिया में होता है। सिंक्रोनस XMLHttpRequest का ऐतिहासिक रूप से यहीं दुरुपयोग किया जाता रहा है — रिक्वेस्ट पूरी होने तक नेविगेशन को रोकने के लिए — जिससे रिस्पॉन्सिवनेस को नुकसान पहुँचता है। आधुनिक ब्राउज़र इसे सक्रिय रूप से हतोत्साहित करते हैं, और unload के दौरान शुरू की गई रिक्वेस्ट अक्सर रद्द कर दी जाती हैं। Beacon स्पेसिफिकेशन ठीक इसी समस्या को हल करने के लिए मौजूद है: यह किसी पेज को एक ऐसी रिक्वेस्ट शेड्यूल करने देता है, जिसे यूज़र एजेंट asynchronously, अगले पेज की लोडिंग को रोके बिना, भेजने की कोशिश करने की गारंटी देता है।
एनालिटिक्स के लिए इसका व्यावहारिक निहितार्थ यह है: beforeunload/unload हैंडलर से चलाए गए सामान्य fetch या XHR पर कभी भरोसा न करें। हो सकता है कि वह डिवाइस को छोड़कर बाहर ही न निकल पाए।
navigator.sendBeacon
sendBeacon को खासतौर पर इसी काम के लिए बनाया गया है। यह एक छोटा POST क्यू में डालता है और तुरंत एक बूलियन लौटाता है, जो केवल यह बताता है कि रिक्वेस्ट सफलतापूर्वक क्यू में डाली गई या नहीं — यह नहीं कि वह सफल हुई या नहीं। इसके बाद ब्राउज़र इसे बैकग्राउंड में भेजता है, भले ही पेज जा चुका हो।
const ok = navigator.sendBeacon('/collect', payload);
इसकी ताकतें:
- ट्रांसफर दस्तावेज़ के जीवनकाल से बंधा नहीं है।
- यह कम प्राथमिकता वाला है और अगले नेविगेशन के साथ प्रतिस्पर्धा न करने के लिए डिज़ाइन किया गया है।
- कोई रिस्पॉन्स हैंडलिंग नहीं है, इसलिए इंतज़ार करने के लिए कुछ भी नहीं है।
स्पेसिफिकेशन और ब्राउज़र इम्प्लीमेंटेशन के अनुसार सीमाएँ:
- केवल POST। आप मनमाने मेथड सेट नहीं कर सकते।
- हेडर्स पर सीमित नियंत्रण।
Content-Typeपेलोड के प्रकार से अनुमानित होता है (उदाहरण के लिए,Blobआपको इसे प्रभावित करने देता है, लेकिन आप कस्टम रिक्वेस्ट हेडर्स स्वतंत्र रूप से सेट नहीं कर सकते)। - पेलोड यूज़र एजेंट की डेटा सीमा में गिने जाते हैं; बहुत बड़े beacon
falseलौटाते हैं।
कुकी-रहित एनालिटिक्स के लिए, आमतौर पर इतना ही पर्याप्त है — बहुत सारे ट्रैकर बिल्कुल यही लागू करते हैं और फिर कभी पीछे मुड़कर नहीं देखते। Monoid ऐसा नहीं करता, एक खास वजह से: sendBeacon mode: 'cors' व्यक्त नहीं कर सकता, और Monoid का इंस्टॉल स्निपेट किसी साइट को data-api-url को होस्ट पेज से अलग origin पर पॉइंट करने देता है। यही एक सीमा नीचे दी गई तुलना का फैसला करती है।
keepalive के साथ fetch
Fetch स्टैंडर्ड एक keepalive फ्लैग परिभाषित करता है जो किसी रिक्वेस्ट को उसे शुरू करने वाले पेज से आगे भी जीवित रखता है, जिससे आपको एक ज़्यादा समृद्ध API के साथ sendBeacon जैसी टिकाऊपन मिलती है।
fetch('/collect', {
method: 'POST',
keepalive: true,
headers: { 'Content-Type': 'application/json' },
body: payload,
});
इसकी ताकतें:
- मेथड, हेडर्स और बॉडी पर पूरा नियंत्रण।
- एक असली
Responseजिसे आप जाँच सकते हैं (हालाँकि अनलोड के दौरान अक्सर आपको इसका इंतज़ार नहीं करना चाहिए)।
सीमाएँ:
- Fetch स्पेसिफिकेशन एक दस्तावेज़ में चल रही सभी keepalive रिक्वेस्ट की कुल बॉडी साइज़ को 64 KiB तक सीमित करता है। इसे पार करने पर fetch अस्वीकार हो जाता है। यह एक प्रति-दस्तावेज़ बजट है, इसलिए कई समवर्ती keepalive रिक्वेस्ट इसे साझा करती हैं।
- ऐतिहासिक रूप से,
keepaliveका सपोर्टsendBeaconसे पीछे रहा है, और इसमें इम्प्लीमेंटेशन की कुछ विचित्रताएँ रही हैं। उन्हीं ब्राउज़रों पर टेस्ट करें जिन्हें आपकी ऑडियंस वास्तव में इस्तेमाल करती है।
यही वह तरीका है जिसे Monoid का ट्रैकर हर रिक्वेस्ट के लिए इस्तेमाल करता है — /collect, /duration और /event सभी में समान रूप से:
fetch(endpoint, {
method: 'POST',
body: JSON.stringify(payload),
headers: { 'Content-Type': 'application/json' },
keepalive: true,
mode: 'cors',
});
पिछले सेक्शन का निर्णायक कारक mode: 'cors' है, न कि पेलोड साइज़ या हेडर्स की संख्या — यह याद रखने लायक है, क्योंकि ज़्यादातर लेख इस चुनाव को पूरी तरह साइज़ के इर्द-गिर्द फ्रेम करते हैं।
किसे चुनें
एक व्यावहारिक नियम: sendBeacon का इस्तेमाल फायर-एंड-फॉरगेट टेलीमेट्री के लिए करें, जहाँ आपको वापस कुछ नहीं चाहिए, और fetch keepalive की ओर तभी जाएँ जब आपको वाकई कस्टम हेडर्स, एक बड़ी संरचित रिक्वेस्ट, या क्रॉस-ऑरिजिन mode नियंत्रण की ज़रूरत हो। किसी भी सूरत में पेलोड छोटे रखें — keepalive के 64 KiB बजट से कहीं कम — क्योंकि एनालिटिक्स इवेंट डिज़ाइन से ही न्यूनतम होने चाहिए। डेटा मिनिमाइज़ेशन केवल एक कंप्लायंस रवैया नहीं है; यही वह चीज़ है जो अनलोड के दौरान भरोसेमंद डिलीवरी को संभव बनाती है। Monoid वह अपवाद है जिसे यह नियम पहले से ध्यान में रखता है: पेलोड छोटा है और रिस्पॉन्स कभी नहीं पढ़ा जाता — बिल्कुल वही प्रोफ़ाइल जिसके लिए sendBeacon बनाया गया था — लेकिन mode: 'cors' का सपोर्ट निर्णायक साबित होता है।
किस इवेंट को सुनना सही है
unload को न पकड़ें। यह भरोसेमंद नहीं है और back/forward cache (bfcache) को तोड़ देता है। Page Lifecycle की गाइडेंस visibilitychange को सुनने और hidden में ट्रांज़िशन को अपना आखिरी भरोसेमंद पल मानने की सलाह देती है, जब डेटा फ्लश किया जाना चाहिए। यह डेस्कटॉप पर बंद होने, टैब स्विच करने, और मोबाइल पर ऐप बैकग्राउंडिंग — इन सभी मामलों में लगातार काम करता है, जहाँ unload कभी ट्रिगर ही नहीं होता।
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') flush();
});
Monoid का ट्रैकर इसी पैटर्न का पालन करता है: एक visibilitychange लिसनर एक beforeunload फॉलबैक के साथ मौजूद रहता है, ताकि चाहे टैब मोबाइल पर बैकग्राउंड में भेजा जाए या डेस्कटॉप पर पूरी तरह बंद किया जाए, हर हाल में एक ड्यूरेशन सैंपल रिपोर्ट हो।
यह कुकी-रहित मॉडल में कैसे फिट बैठता है
चूँकि Monoid कभी कुकी या स्टोरेज नहीं पढ़ता और कभी फिंगरप्रिंटिंग नहीं करता, इसलिए हर रिक्वेस्ट केवल वही जानकारी ले जाती है जो वह वैसे भी उजागर करती है — एक मोटा-सा इवेंट, साथ ही वे हेडर्स जो ब्राउज़र वैसे भी भेजता है। कोई ऐसा आइडेंटिफायर नहीं है जिसे बनाए रखना पड़े, इसलिए स्टेट सिंक करने के लिए हमें कभी किसी दो-तरफा एक्सचेंज की ज़रूरत नहीं पड़ती। यही वह वजह है जो mode: 'cors' द्वारा sendBeacon को बाहर करते ही fetch keepalive को सहज चुनाव बना देती है: एक ऐसा वन-शॉट POST जिसका रिस्पॉन्स हम कभी नहीं देखते, यह हमारे लिए कोई सीमा नहीं है; बल्कि यही वह चीज़ है जो डिलीवरी की भरोसेमंदता को प्राइवेसी बाय डिज़ाइन के साथ संरेखित करती है।
Comments
Loading comments…