काम और आंतरिक उपकरण एक्सप्रेस की विशेषताएं। जेएस

यदि आप प्लेटफ़ॉर्म नोड.जेएस के लिए विकसित कर रहे थे, तो आपने शायद एक्सप्रेस.जेएस के बारे में सुना था। यह नोड के लिए वेब एप्लिकेशन बनाने के लिए उपयोग किए जाने वाले सबसे लोकप्रिय हल्के फ्रेमवर्क में से एक है।



सामग्री के लेखक, जिसका अनुवाद आज हम प्रकाशित करते हैं, अपने स्रोत कोड के विश्लेषण के माध्यम से एक्सप्रेस ढांचे की आंतरिक संरचना की विशेषताओं का अध्ययन करने और इसके उपयोग के एक उदाहरण पर विचार करने की पेशकश करता है। उनका मानना ​​है कि लोकप्रिय ओपन सोर्स पुस्तकालयों में अंतर्निहित तंत्र का अध्ययन उनके बारे में गहरी समझ के लिए योगदान देता है, उनसे "रहस्य" का पर्दा हटाता है और उनके आधार पर बेहतर एप्लिकेशन बनाने में मदद करता है।

इस सामग्री को पढ़ते समय एक्सप्रेस स्रोत कोड को रखना आपको सुविधाजनक लग सकता है। इस संस्करण का उपयोग यहां किया गया है। आप एक्सप्रेस कोड को खोले बिना इस लेख को पढ़ सकते हैं, यहाँ से, जहाँ भी उपयुक्त हो, इस पुस्तकालय के कोड टुकड़े दिए गए हैं। उन स्थानों पर जहां कोड संक्षिप्त है, प्रपत्र // ... की टिप्पणियों का // ...

एक्सप्रेस का उपयोग करने का एक मूल उदाहरण


शुरुआत करने के लिए, आइए एक नज़र डालें "हैलो वर्ल्ड!" नई कंप्यूटर तकनीकों के विकास में पारंपरिक - एक उदाहरण। यह ढांचे की आधिकारिक वेबसाइट पर पाया जा सकता है, यह हमारे शोध में एक शुरुआती बिंदु के रूप में काम करेगा।

 const express = require('express') const app = express() app.get('/', (req, res) => res.send('Hello World!')) app.listen(3000, () => console.log('Example app listening on port 3000!')) 

यह कोड पोर्ट 3000 पर एक नया HTTP सर्वर शुरू करता है और एक Hello World! भेजता है Hello World! GET / मार्ग पर प्राप्त अनुरोधों के लिए। यदि आप विवरण में नहीं जाते हैं, तो हम चार चरणों में अंतर कर सकते हैं कि क्या हो रहा है, जिसका हम विश्लेषण कर सकते हैं:

  1. एक नया एक्सप्रेस एप्लिकेशन बनाएं।
  2. एक नया मार्ग बनाएँ।
  3. निर्दिष्ट पोर्ट नंबर पर HTTP सर्वर शुरू करना।
  4. सर्वर के लिए आने वाले अनुरोधों को संसाधित करना।

एक नया एक्सप्रेस एप्लिकेशन बनाना


var app = express() कमांड आपको एक नया एक्सप्रेस एप्लिकेशन बनाने की अनुमति देता है। Lib / express.js फ़ाइल से createApplication फ़ंक्शन डिफ़ॉल्ट निर्यात फ़ंक्शन है; यह हम है जो express() फ़ंक्शन को कॉल करके इसे एक्सेस करते हैं। यहां कुछ महत्वपूर्ण बातें हैं जिन पर आपको ध्यान देना चाहिए:

 // ... var mixin = require('merge-descriptors'); var proto = require('./application'); // ... function createApplication() { //    ,     . //     : `function(req, res, next)` var app = function(req, res, next) {   app.handle(req, res, next); }; // ... //  `mixin`    `proto`  `app` //     -  `get`,     . mixin(app, proto, false); // ... return app; } 

इस फ़ंक्शन से दी गई app ऑब्जेक्ट हमारे एप्लिकेशन कोड में उपयोग की जाने वाली वस्तुओं में से एक है। app.get पद्धति app.get मर्ज-डिस्क्रिप्टर लाइब्रेरी के app.get फ़ंक्शन का उपयोग करके जोड़ा app.get , जो proto में घोषित app विधियों को असाइन करने के लिए जिम्मेदार है। proto ऑब्जेक्ट स्वयं ही lib / application.js से आयात किया जाता है।

एक नया मार्ग बनाएँ


अब आइए उस कोड को देखें जो हमारे उदाहरण से app.get विधि बनाने के लिए जिम्मेदार है।

 var slice = Array.prototype.slice; // ... /** *   `.VERB(...)` `router.VERB(...)`. */ // `methods`    HTTP, (  ['get','post',...]) methods.forEach(function(method){ //    app.get app[method] = function(path){   //     //          var route = this._router.route(path);   //        route[method].apply(route, slice.call(arguments, 1));   //   `app`,          return this; }; }); 

यह ध्यान रखना दिलचस्प है कि, सिमेंटिक फीचर्स के अलावा, HTTP क्रियाओं को लागू करने वाले सभी तरीके, जैसे कि app.get , app.post , app.put और जैसे, कार्यक्षमता के मामले में, समान माना जा सकता है। यदि आप उपर्युक्त कोड को सरल करते हैं, तो इसे केवल एक विधि get करने के लिए कम करके, आपको निम्न जैसा कुछ मिलेगा:

 app.get = function(path, handler){ // ... var route = this._router.route(path); route.get(handler) return this } 

यद्यपि उपरोक्त फ़ंक्शन के 2 तर्क हैं, यह फ़ंक्शन app[method] = function(path){...} । दूसरा तर्क, handler , slice.call(arguments, 1) को कॉल करके प्राप्त किया जाता है।

संक्षेप में, app.<method> बस अपने route विधि का उपयोग करके एप्लिकेशन राउटर में मार्ग को बचाता है, और फिर handler को route.<method>

राउटर route() राउटर विधि को लिबर / राउटर / इंडेक्स में घोषित किया गया है।

 // proto -     `_router` proto.route = function route(path) { var route = new Route(path); var layer = new Layer(path, {   sensitive: this.caseSensitive,   strict: this.strict,   end: true }, route.dispatch.bind(route)); layer.route = route; this.stack.push(layer); return route; }; 

route.get , lib / राउटर / मार्ग में route.get विधि की घोषणा app.get की घोषणा के app.get :

 methods.forEach(function (method) { Route.prototype[method] = function () {   // `flatten`   ,  [1,[2,3]],      var handles = flatten(slice.call(arguments));   for (var i = 0; i < handles.length; i++) {     var handle = handles[i];         // ...     //   ,  ,    Layer,     //            var layer = Layer('/', {}, handle);     // ...     this.stack.push(layer);   }   return this; }; }); 

प्रत्येक मार्ग में कई हैंडलर हो सकते हैं, प्रत्येक हैंडलर के आधार पर, टाइप Layer एक चर का निर्माण किया जाता है, जो एक डाटा प्रोसेसिंग लेयर है, जो तब स्टैक पर मिलती है।

परतदार वस्तुएं


_router और route दोनों प्रकार की वस्तुओं का उपयोग करते हैं। ऐसी वस्तु के सार को समझने के लिए, आइए इसके निर्माता को देखें :

 function Layer(path, options, fn) { // ... this.handle = fn; this.regexp = pathRegexp(path, this.keys = [], opts); // ... } 

टाइप Layer ऑब्जेक्ट बनाते समय Layer उन्हें एक पथ, कुछ पैरामीटर और एक फंक्शन दिया जाता है। हमारे राउटर के मामले में, यह फ़ंक्शन route.dispatch है। route.dispatch (हम इसके बारे में अधिक बात करेंगे, सामान्य शब्दों में, इसे एक अलग मार्ग के लिए अनुरोध प्रेषित करने के लिए डिज़ाइन किया गया है)। मार्ग के मामले में, यह फ़ंक्शन हमारे उदाहरण के कोड में घोषित हैंडलर फ़ंक्शन है।

टाइप Layer प्रत्येक ऑब्जेक्ट में एक हैंडल_रेक्वेस्ट विधि होती है, जो ऑब्जेक्ट को इनिशियलाइज़ किए जाने पर पारित फ़ंक्शन को निष्पादित करने के लिए ज़िम्मेदार होती है।

app.get पद्धति का उपयोग करके मार्ग बनाते समय क्या होता है उसे याद करें:

  1. एप्लिकेशन के राउटर में एक मार्ग बनाया गया है ( this._router )।
  2. dispatch मार्ग विधि को संबंधित Layer ऑब्जेक्ट के हैंडलर विधि के रूप में सौंपा गया है, और यह ऑब्जेक्ट राउटर स्टैक पर धकेल दिया जाता है।
  3. अनुरोध हैंडलर को Layer ऑब्जेक्ट को हैंडलर विधि के रूप में पास किया जाता है, और इस ऑब्जेक्ट को रूट स्टैक पर धकेल दिया जाता है।

नतीजतन, सभी हैंडलर app उदाहरण के अंदर Layer टाइप की वस्तुओं के रूप में संग्रहीत किए जाते हैं जो रूट स्टैक के अंदर होते हैं, जिनके राउटर Layer ऑब्जेक्ट को राउटर स्टैक में दिए जाते हैं:


राउटर स्टैक और रूट स्टैक पर लेट ऑब्जेक्ट

इनकमिंग HTTP अनुरोध इस तर्क के अनुसार संसाधित किए जाते हैं। हम उनके बारे में नीचे बात करेंगे।

HTTP सर्वर स्टार्टअप


मार्गों को कॉन्फ़िगर करने के बाद, आपको सर्वर शुरू करने की आवश्यकता है। हमारे उदाहरण में, हम app.listen पद्धति की ओर app.listen , इसे पोर्ट नंबर और कॉलबैक फ़ंक्शन को तर्कों के रूप में पास करते हैं। इस पद्धति की विशेषताओं को समझने के लिए, हम lib / application.js फ़ाइल का संदर्भ ले सकते हैं:

 app.listen = function listen() { var server = http.createServer(this); return server.listen.apply(server, arguments); }; 

app.listen आसपास सिर्फ एक आवरण है। यह दृष्टिकोण समझ में आता है, क्योंकि यदि आप याद करते हैं कि हमने बहुत शुरुआत में क्या बात की थी, तो app केवल एक फ़ंक्शन है जिसमें हस्ताक्षर function(req, res, next) {...} , जो http.createServer लिए आवश्यक तर्कों के साथ संगत है http.createServer (इस पद्धति का हस्ताक्षर function (req, res) {...} ) है।

यह महसूस करने के बाद, अंत में, जो कुछ भी व्यक्त करता है। जेएस हमें देता है उसे एक बहुत ही बुद्धिमान फ़ंक्शन-हैंडलर में कम किया जा सकता है, रूपरेखा अब पहले की तरह जटिल और रहस्यमय नहीं लगती है।

HTTP अनुरोध प्रसंस्करण


अब जब हम जानते हैं कि app केवल एक अनुरोध हैंडलर है, तो हम उस पथ का अनुसरण करेंगे जो एक HTTP एप्लिकेशन एक्सप्रेस एप्लिकेशन के अंदर से गुजरता है। यह रास्ता हमारे द्वारा घोषित हैंडलर की ओर ले जाता है।

सबसे पहले, अनुरोध createApplication फ़ंक्शन ( lib / express.js ) पर जाता है:

 var app = function(req, res, next) {   app.handle(req, res, next); }; 

फिर यह app.handle मेथड ( lib / application.js ) पर जाता है:

 app.handle = function handle(req, res, callback) { // `this._router` -  ,    ,  `app.get` var router = this._router; // ... //     `handle` router.handle(req, res, done); }; 

router.handle मेथड lib / रूटर / index.js में घोषित किया गया है:

 proto.handle = function handle(req, res, out) { var self = this; //... // self.stack -  ,      // Layer (  ) var stack = self.stack; // ... next(); function next(err) {   // ...   //        var path = getPathname(req);   // ...   var layer;   var match;   var route;   while (match !== true && idx < stack.length) {     layer = stack[idx++];     match = matchLayer(layer, path);     route = layer.route;     // ...     if (match !== true) {       continue;     }     // ...      HTTP,       }  // ...      // process_params    ,          self.process_params(layer, paramcalled, req, res, function (err) {     // ...     if (route) {       //       `layer.handle_request`       //         `next`       //  ,   `next`     ,              //  ,   `next`   ,            return layer.handle_request(req, res, next);     }     // ...   }); } }; 

यदि आप वर्णन करते हैं कि संक्षेप में क्या हो रहा है, तो router.handle फ़ंक्शन स्टैक पर सभी परतों से गुजरता है जब तक कि वह उस एक को नहीं पाता जो अनुरोध में निर्दिष्ट पथ से मेल खाता है। फिर, handle_request लेयर विधि को बुलाया जाएगा, जो पूर्वनिर्धारित हैंडलर फ़ंक्शन को निष्पादित करेगा। यह हैंडलर फंक्शन एक dispatch रूट मेथड है, जो लिब / रूट / जो रूट में घोषित किया गया है:

 Route.prototype.dispatch = function dispatch(req, res, done) { var stack = this.stack; // ... next(); function next(err) {   // ...   var layer = stack[idx++];   // ...    layer.handle_request(req, res, next);   // ... } }; 

जिस तरह राउटर के मामले में, प्रत्येक मार्ग के प्रसंस्करण के दौरान, इस मार्ग की परतों की गणना की जाती है और लेयर हैंडलर विधियों को अंजाम देने वाले उनके handle_request तरीकों को handle_request । हमारे मामले में, यह एक अनुरोध हैंडलर है, जिसे एप्लिकेशन कोड में घोषित किया गया है।

यहां, अंत में, HTTP अनुरोध हमारे आवेदन के कोड क्षेत्र में आता है।


एक्सप्रेस आवेदन में पथ का अनुरोध करें

परिणाम


यहां हमने एक्सप्रेस.जेएस लाइब्रेरी के केवल मूल तंत्रों की जांच की, जो वेब सर्वर के संचालन के लिए जिम्मेदार हैं, लेकिन इस लाइब्रेरी में कई अन्य विशेषताएं भी हैं। हम हैंडलर तक पहुंचने से पहले अनुरोधों को चेक से रोकते नहीं थे, हम उन सहायक विधियों के बारे में बात नहीं करते थे जो res और req चर के साथ काम करते समय उपलब्ध होते हैं। और अंत में, हम एक्सप्रेस की सबसे शक्तिशाली विशेषताओं में से एक पर स्पर्श नहीं किया। इसमें मिडलवेयर का उपयोग होता है, जिसका उद्देश्य लगभग किसी भी समस्या को हल करने के लिए किया जा सकता है - पार्स करने के अनुरोध से लेकर एक संपूर्ण प्रमाणीकरण प्रणाली लागू करने तक।

हमें उम्मीद है कि इस सामग्री ने आपको एक्सप्रेस डिवाइस की मुख्य विशेषताओं को समझने में मदद की, और अब, यदि आवश्यक हो, तो आप इस पुस्तकालय के स्रोत कोड के कुछ हिस्सों का स्वतंत्र रूप से विश्लेषण करके बाकी सब समझ सकते हैं जो आपकी रुचि रखते हैं।

प्रिय पाठकों! क्या आप एक्सप्रेस.जेएस का उपयोग करते हैं?

Source: https://habr.com/ru/post/hi414079/


All Articles