परिचय
HTML5 यूनिवर्स में XMLHttpRequest
एक ऐसा हीरो है जिसकी ज़्यादा चर्चा नहीं होती.
असल में, XHR2, HTML5 नहीं है. हालांकि, यह कोर प्लैटफ़ॉर्म में ब्राउज़र वेंडर के किए जा रहे सुधारों का हिस्सा है. हम XHR2 को अपने नए बैग में शामिल कर रहे हैं, क्योंकि यह आज के जटिल वेब ऐप्लिकेशन में अहम भूमिका निभाता है.
पता चला है कि हमारे पुराने दोस्त को काफ़ी बदलाव किया गया है. हालांकि, कई लोगों को इसकी नई सुविधाओं के बारे में पता नहीं है. XMLHttpRequest लेवल 2 में कई नई सुविधाएं जोड़ी गई हैं. इनकी मदद से, हमारे वेब ऐप्लिकेशन में हैकिंग की जटिल समस्याओं को हल किया जा सकता है. जैसे, क्रॉस-ऑरिजिन अनुरोध, प्रोग्रेस इवेंट अपलोड करना, और बाइनरी डेटा अपलोड/डाउनलोड करने की सुविधा. इनकी मदद से, AJAX को फ़ाइल सिस्टम एपीआई, वेब ऑडियो एपीआई, और WebGL जैसे कई नए HTML5 एपीआई के साथ काम करने की अनुमति मिलती है.
इस ट्यूटोरियल में, XMLHttpRequest
की कुछ नई सुविधाओं के बारे में बताया गया है. इनमें से खास तौर पर, फ़ाइलों के साथ काम करने के लिए इस्तेमाल की जा सकने वाली सुविधाओं के बारे में बताया गया है.
डेटा फ़ेच करना
XHR की मदद से, किसी फ़ाइल को बाइनरी ब्लॉब के तौर पर फ़ेच करना मुश्किल होता है. तकनीकी तौर पर, ऐसा करना भी मुमकिन नहीं था. एक ऐसी तरकीब है जिसे अच्छी तरह से दस्तावेज़ में दर्ज किया गया है. इसमें, उपयोगकर्ता के तय किए गए शॉर्ट कोड के साथ mime टाइप को बदलना शामिल है, जैसा कि नीचे देखा गया है.
इमेज फ़ेच करने का पुराना तरीका:
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
// Hack to pass bytes through unprocessed.
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function(e) {
if (this.readyState == 4 && this.status == 200) {
var binStr = this.responseText;
for (var i = 0, len = binStr.length; i < len; ++i) {
var c = binStr.charCodeAt(i);
//String.fromCharCode(c & 0xff);
var byte = c & 0xff; // byte at offset i
}
}
};
xhr.send();
यह तरीका काम करता है, लेकिन responseText
में आपको जो वैल्यू मिलती है वह बाइनरी ब्लॉब नहीं होती. यह इमेज फ़ाइल को दिखाने वाली बाइनरी स्ट्रिंग होती है.
हम सर्वर को गुमराह करके, प्रोसेस नहीं किया गया डेटा वापस भेज रहे हैं.
भले ही, यह तरीका काम करता है, लेकिन मैं इसे काला जादू कहूंगा और इसका इस्तेमाल करने के ख़िलाफ़ सलाह दूंगा. जब भी डेटा को अपने हिसाब से फ़ॉर्मैट में बदलने के लिए, वर्ण कोड हैक और स्ट्रिंग में बदलाव करने की ज़रूरत पड़ती है, तो यह समस्या होती है.
रिस्पॉन्स का फ़ॉर्मैट तय करना
पिछले उदाहरण में, हमने सर्वर के एमआईएम टाइप को बदलकर और रिस्पॉन्स टेक्स्ट को बाइनरी स्ट्रिंग के तौर पर प्रोसेस करके, इमेज को बाइनरी "फ़ाइल" के तौर पर डाउनलोड किया था.
इसके बजाय, ब्राउज़र को यह बताने के लिए कि हमें डेटा किस फ़ॉर्मैट में चाहिए, XMLHttpRequest
की नई
responseType
और response
प्रॉपर्टी का इस्तेमाल करें.
- xhr.responseType
- अनुरोध भेजने से पहले, अपनी डेटा ज़रूरतों के हिसाब से
xhr.responseType
को "टेक्स्ट", "arraybuffer", "blob" या "document" पर सेट करें. ध्यान दें,xhr.responseType = ''
सेट करने या इसे छोड़ने पर, रिस्पॉन्स डिफ़ॉल्ट रूप से "टेक्स्ट" पर सेट हो जाएगा. - xhr.response
- अनुरोध पूरा होने के बाद, xhr की रिस्पॉन्स प्रॉपर्टी में, अनुरोध किया गया डेटा
DOMString
,ArrayBuffer
,Blob
याDocument
के तौर पर दिखेगा. यह इस बात पर निर्भर करता है किresponseType
के लिए क्या सेट किया गया था.
इस नए तरीके की मदद से, हम पिछले उदाहरण को फिर से तैयार कर सकते हैं. हालांकि, इस बार इमेज को स्ट्रिंग के बजाय Blob
के तौर पर फ़ेच किया जाएगा:
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
// Note: .response instead of .responseText
var blob = new Blob([this.response], {type: 'image/png'});
...
}
};
xhr.send();
बहुत अच्छा!
ArrayBuffer के जवाब
ArrayBuffer
एक सामान्य कंटेनर है, जिसमें बाइनरी डेटा को तय लंबाई में सेव किया जाता है. अगर आपको रॉ डेटा का सामान्य बफ़र चाहिए, तो ये बहुत काम के होते हैं. हालांकि, इनकी असली खासियत यह है कि JavaScript टाइप किए गए ऐरे का इस्तेमाल करके, डेटा के "व्यू" बनाए जा सकते हैं.
असल में, एक ही ArrayBuffer
सोर्स से कई व्यू बनाए जा सकते हैं.
उदाहरण के लिए, 8-बिट का ऐसा इंटिजर कलेक्शन बनाया जा सकता है जो उसी डेटा से बने मौजूदा 32-बिट इंटिजर कलेक्शन के ArrayBuffer
के बराबर हो. डेटा एक जैसा ही रहता है, हम सिर्फ़ उसका अलग-अलग तरीके से इस्तेमाल करते हैं.
उदाहरण के लिए, यह कोड हमारी इमेज को ArrayBuffer
के तौर पर फ़ेच करता है,
लेकिन इस बार, उस डेटा बफ़र से बिना साइन वाला 8-बिट इंटिजर कलेक्शन बनाता है:
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
var uInt8Array = new Uint8Array(this.response); // this.response == uInt8Array.buffer
// var byte3 = uInt8Array[4]; // byte at offset 4
...
};
xhr.send();
ब्लॉब के तौर पर जवाब
अगर आपको सीधे Blob
के साथ काम करना है और/या आपको फ़ाइल के किसी भी बाइट में बदलाव करने की ज़रूरत नहीं है, तो xhr.responseType='blob'
का इस्तेमाल करें:
window.URL = window.URL || window.webkitURL; // Take care of vendor prefixes.
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = this.response;
var img = document.createElement('img');
img.onload = function(e) {
window.URL.revokeObjectURL(img.src); // Clean up after yourself.
};
img.src = window.URL.createObjectURL(blob);
document.body.appendChild(img);
...
}
};
xhr.send();
Blob
का इस्तेमाल कई जगहों पर किया जा सकता है. जैसे, इसे indexedDB में सेव करना, इसे एचटीएमएल5 फ़ाइल सिस्टम में लिखना या ब्लॉब यूआरएल बनाना. इस उदाहरण में, इन सभी के बारे में बताया गया है.
डेटा भेजना
डेटा को अलग-अलग फ़ॉर्मैट में डाउनलोड करना बहुत अच्छा है. हालांकि, अगर हम इन रिच फ़ॉर्मैट को होम बेस (सर्वर) पर वापस नहीं भेज सकते, तो इससे हमें कोई फ़ायदा नहीं मिलेगा.
XMLHttpRequest
ने कुछ समय के लिए, DOMString
या Document
(एक्सएमएल) डेटा भेजने पर पाबंदी लगा दी है. अब नहीं. इनमें से किसी भी टाइप को स्वीकार करने के लिए, send()
के बेहतर तरीके को बदल दिया गया है:
DOMString
, Document
, FormData
, Blob
,
File
, ArrayBuffer
. इस सेक्शन के बाकी उदाहरणों में, हर टाइप का इस्तेमाल करके डेटा भेजने का तरीका बताया गया है.
स्ट्रिंग डेटा भेजना: xhr.send(DOMString)
function sendText(txt) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) {
if (this.status == 200) {
console.log(this.responseText);
}
};
xhr.send(txt);
}
sendText('test string');
function sendTextNew(txt) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.responseType = 'text';
xhr.onload = function(e) {
if (this.status == 200) {
console.log(this.response);
}
};
xhr.send(txt);
}
sendTextNew('test string');
यहां कुछ नया नहीं है, हालांकि दाईं ओर मौजूद स्निपेट थोड़ा अलग है.
यह तुलना के लिए responseType='text'
सेट करता है. फिर से, उस लाइन को हटाने पर भी वही नतीजे मिलते हैं.
फ़ॉर्म सबमिट करना: xhr.send(FormData)
हो सकता है कि कई लोगों को AJAX फ़ॉर्म सबमिशन को मैनेज करने के लिए, jQuery प्लग इन या अन्य लाइब्रेरी का इस्तेमाल करने की आदत हो. इसके बजाय, हम FormData
का इस्तेमाल कर सकते हैं. यह XHR2 के लिए बनाया गया एक और नया डेटा टाइप है. FormData
JavaScript में, फ़्लाइट के दौरान एचटीएमएल <form>
बनाने के लिए सुविधाजनक है.
इसके बाद, उस फ़ॉर्म को AJAX का इस्तेमाल करके सबमिट किया जा सकता है:
function sendForm() {
var formData = new FormData();
formData.append('username', 'johndoe');
formData.append('id', 123456);
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
xhr.send(formData);
}
असल में, हम डाइनैमिक तौर पर <form>
बना रहे हैं और append तरीके को कॉल करके, उसमें <input>
वैल्यू जोड़ रहे हैं.
हालांकि, आपको <form>
को शुरू से बनाने की ज़रूरत नहीं है.
FormData
ऑब्जेक्ट को पेज पर मौजूद HTMLFormElement
से शुरू किया जा सकता है. उदाहरण के लिए:
<form id="myform" name="myform" action="/server">
<input type="text" name="username" value="johndoe">
<input type="number" name="id" value="123456">
<input type="submit" onclick="return sendForm(this.form);">
</form>
function sendForm(form) {
var formData = new FormData(form);
formData.append('secret_token', '1234567890'); // Append extra data before send.
var xhr = new XMLHttpRequest();
xhr.open('POST', form.action, true);
xhr.onload = function(e) { ... };
xhr.send(formData);
return false; // Prevent page from submitting.
}
एचटीएमएल फ़ॉर्म में फ़ाइल अपलोड (उदाहरण के लिए, <input type="file">
) शामिल हो सकते हैं और FormData
भी उन्हें मैनेज कर सकता है. बस फ़ाइलें जोड़ें और send()
को कॉल करने पर, ब्राउज़र multipart/form-data
अनुरोध बना देगा:
function uploadFiles(url, files) {
var formData = new FormData();
for (var i = 0, file; file = files[i]; ++i) {
formData.append(file.name, file);
}
var xhr = new XMLHttpRequest();
xhr.open('POST', url, true);
xhr.onload = function(e) { ... };
xhr.send(formData); // multipart/form-data
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
uploadFiles('/server', this.files);
}, false);
कोई फ़ाइल या ब्लॉब अपलोड करना: xhr.send(Blob)
हम XHR का इस्तेमाल करके, File
या Blob
डेटा भी भेज सकते हैं.
ध्यान रखें कि सभी File
, Blob
होते हैं. इसलिए, यहां दोनों में से कोई भी काम करेगा.
इस उदाहरण में, Blob()
कन्स्ट्रक्टर का इस्तेमाल करके, एक नई टेक्स्ट फ़ाइल बनाई गई है और उसे सर्वर पर अपलोड किया गया है.Blob
यह कोड, उपयोगकर्ता को अपलोड की प्रोग्रेस के बारे में बताने के लिए एक हैंडलर भी सेट अप करता है:
<progress min="0" max="100" value="0">0% complete</progress>
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
// Listen to the upload progress.
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
upload(new Blob(['hello world'], {type: 'text/plain'}));
बाइट का एक हिस्सा अपलोड करना: xhr.send(ArrayBuffer)
आखिर में, हम XHR के पेलोड के तौर पर ArrayBuffer
भेज सकते हैं.
function sendArrayBuffer() {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
var uInt8Array = new Uint8Array([1, 2, 3]);
xhr.send(uInt8Array.buffer);
}
क्रॉस-ऑरिजिन रिसॉर्स शेयरिंग (सीओआरएस)
CORS की मदद से, एक डोमेन पर मौजूद वेब ऐप्लिकेशन, दूसरे डोमेन पर क्रॉस-डोमेन AJAX अनुरोध कर सकते हैं. इसे चालू करना बहुत आसान है. इसके लिए, सर्वर को सिर्फ़ एक रिस्पॉन्स हेडर भेजना होता है.
सीओआरएस अनुरोधों को चालू करना
मान लें कि आपका ऐप्लिकेशन example.com
पर मौजूद है और आपको www.example2.com
से डेटा चाहिए. आम तौर पर, अगर इस तरह का AJAX कॉल करने की कोशिश की जाती है, तो अनुरोध पूरा नहीं होगा और ब्राउज़र, ऑरिजिन मैच न होने की गड़बड़ी दिखाएगा. सीओआरएस की मदद से, www.example2.com
सिर्फ़ एक हेडर जोड़कर, example.com
से आने वाले अनुरोधों को अनुमति दे सकता है:
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Origin
को किसी साइट के तहत मौजूद एक संसाधन या पूरे डोमेन में जोड़ा जा सकता है. किसी भी डोमेन को आपसे अनुरोध करने की अनुमति देने के लिए, यह सेट करें:
Access-Control-Allow-Origin: *
असल में, इस साइट (html5rocks.com) ने अपने सभी पेजों पर सीओआरएस की सुविधा चालू की है. डेवलपर टूल चालू करें. आपको हमारे जवाब में Access-Control-Allow-Origin
दिखेगा:
क्रॉस-ऑरिजिन अनुरोधों को चालू करना आसान है. इसलिए, अगर आपका डेटा सार्वजनिक है, तो कृपया सीओआरएस चालू करें!
क्रॉस-डोमेन अनुरोध करना
अगर सर्वर एंडपॉइंट में सीओआरएस चालू है, तो क्रॉस-ऑरिजिन अनुरोध करना, सामान्य XMLHttpRequest
अनुरोध करने से अलग नहीं है. उदाहरण के लिए, यहां एक अनुरोध दिया गया है, जिसे example.com
अब www.example2.com
से कर सकता है:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://www.example2.com/hello.json');
xhr.onload = function(e) {
var data = JSON.parse(this.response);
...
}
xhr.send();
काम के उदाहरण
HTML5 फ़ाइल सिस्टम में फ़ाइलें डाउनलोड और सेव करना
मान लें कि आपके पास एक इमेज गैलरी है और आपको कई इमेज फ़ेच करनी हैं. इसके बाद, उन्हें HTML5 फ़ाइल सिस्टम का इस्तेमाल करके, डिवाइस में सेव करना है.
ऐसा करने का एक तरीका यह है कि इमेज का अनुरोध Blob
s के तौर पर करें और उन्हें FileWriter
का इस्तेमाल करके लिखें:
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
function onError(e) {
console.log('Error', e);
}
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
window.requestFileSystem(TEMPORARY, 1024 * 1024, function(fs) {
fs.root.getFile('image.png', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.onwrite = function(e) { ... };
writer.onerror = function(e) { ... };
var blob = new Blob([xhr.response], {type: 'image/png'});
writer.write(blob);
}, onError);
}, onError);
}, onError);
};
xhr.send();
किसी फ़ाइल को स्लाइस करके, हर हिस्से को अपलोड करना
फ़ाइल एपीआई का इस्तेमाल करके, हम बड़ी फ़ाइल अपलोड करने के काम को कम कर सकते हैं. इस तकनीक में, अपलोड की गई फ़ाइल को कई हिस्सों में बांटा जाता है. इसके बाद, हर हिस्से के लिए एक XHR स्पॉन किया जाता है और फ़ाइल को सर्वर पर एक साथ डाला जाता है. यह उसी तरह है जिस तरह GMail बड़े अटैचमेंट को तेज़ी से अपलोड करता है. इस तरह की तकनीक का इस्तेमाल, Google App Engine के 32 एमबी के एचटीटीपी अनुरोध की सीमा को पार करने के लिए भी किया जा सकता है.
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
xhr.send(blobOrFile);
}
document.querySelector('input[type="file"]').addEventListener('change', function(e) {
var blob = this.files[0];
const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
const SIZE = blob.size;
var start = 0;
var end = BYTES_PER_CHUNK;
while(start < SIZE) {
upload(blob.slice(start, end));
start = end;
end = start + BYTES_PER_CHUNK;
}
}, false);
})();
यहां सर्वर पर फ़ाइल को फिर से बनाने का कोड नहीं दिखाया गया है.
रेफ़रंस
- XMLHttpRequest लेवल 2 स्पेसिफ़िकेशन
- क्रॉस-ऑरिजिन रिसॉर्स शेयरिंग (सीओआरएस) की खास बातें
- File API की खास बातें
- FileSystem API की खास बातें