ओपनरेस्टी डायनामिक अनुरोध और प्रतिक्रियाओं के साथ उन्नत NGINX है
API7.ai
October 23, 2022
पिछले परिचय के बाद, आप OpenResty की अवधारणा और इसे कैसे सीखना है, यह समझ गए होंगे। यह लेख हमें यह बताएगा कि OpenResty क्लाइंट अनुरोधों और प्रतिक्रियाओं को कैसे संभालता है।
हालांकि OpenResty एक NGINX-आधारित वेब सर्वर है, यह NGINX से मूल रूप से अलग है: NGINX स्थिर कॉन्फ़िगरेशन फ़ाइलों द्वारा संचालित होता है, जबकि OpenResty Lua API द्वारा संचालित होता है, जो अधिक लचीलापन और प्रोग्रामेबिलिटी प्रदान करता है।
मैं आपको Lua API के लाभों के बारे में बताऊंगा।
API श्रेणियाँ
सबसे पहले, हमें यह जानना होगा कि OpenResty API को निम्नलिखित व्यापक श्रेणियों में विभाजित किया गया है।
- अनुरोध और प्रतिक्रिया प्रसंस्करण।
- SSL-संबंधित।
- साझा डिक्ट।
- Cosocket।
- चार स्तरों के ट्रैफ़िक को संभालना।
- प्रक्रिया और कार्यकर्ता।
- NGINX वेरिएबल्स और कॉन्फ़िगरेशन तक पहुंच।
- स्ट्रिंग, समय, कोडेक, और अन्य सामान्य कार्य, आदि।
यहां, मैं सुझाव देता हूं कि आप OpenResty का Lua API दस्तावेज़ भी खोलें और API सूची के साथ इसे जांचें कि क्या आप इस श्रेणी से संबंधित हो सकते हैं।
OpenResty API केवल lua-nginx-module प्रोजेक्ट में ही नहीं हैं, बल्कि lua-resty-core प्रोजेक्ट में भी हैं, जैसे ngx.ssl, ngx.base64, ngx.errlog, ngx.process, ngx.re.split, ngx.resp.add_header, ngx.balancer, ngx.semaphore, ngx.ocsp, और अन्य API।
जो API lua-nginx-module प्रोजेक्ट में नहीं हैं, उन्हें उपयोग करने के लिए आपको अलग से require करना होगा। उदाहरण के लिए, यदि आप split फ़ंक्शन का उपयोग करना चाहते हैं, तो आपको इसे निम्नानुसार कॉल करना होगा।
$ resty -e 'local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", ",", nil, {pos = 5}) print(res) '
बेशक, यह आपको भ्रमित कर सकता है: lua-nginx-module प्रोजेक्ट में, ngx.re.sub, ngx.re.find, आदि से शुरू होने वाले कई API हैं। फिर क्यों केवल ngx.re.split API को उपयोग करने से पहले require करने की आवश्यकता है?
जैसा कि हमने पिछले lua-resty-core अध्याय में उल्लेख किया था, नए OpenResty API को lua-rety-core रिपॉजिटरी में FFI के तरीके से लागू किया गया है, इसलिए इसमें विखंडन की भावना अनिवार्य रूप से है। मैं भविष्य में lua-nginx-module और lua-resty-core प्रोजेक्ट्स को मर्ज करके इस समस्या को हल करने की उम्मीद कर रहा हूं।
अनुरोध
अगला, आइए देखें कि OpenResty क्लाइंट अनुरोधों और प्रतिक्रियाओं को कैसे संभालता है। सबसे पहले, आइए अनुरोधों को संभालने के लिए API को देखें, लेकिन ngx.req से शुरू होने वाले 20 से अधिक API हैं, तो हम कैसे शुरू करें?
हम जानते हैं कि HTTP अनुरोध संदेश तीन भागों से बना होता है: अनुरोध लाइन, अनुरोध हेडर, और अनुरोध बॉडी, इसलिए मैं इन तीन भागों में API का परिचय दूंगा।
अनुरोध लाइन
पहले अनुरोध लाइन है, जिसमें HTTP के लिए अनुरोध विधि, URI, और HTTP प्रोटोकॉल संस्करण शामिल होता है। NGINX में, आप इस मान को एक बिल्ट-इन वेरिएबल का उपयोग करके प्राप्त कर सकते हैं, जबकि OpenResty में, यह ngx.var.* API से मेल खाता है। आइए दो उदाहरण देखें।
- बिल्ट-इन वेरिएबल
$scheme, जो NGINX में प्रोटोकॉल का नाम दर्शाता है, या तोhttpयाhttpsहोता है; OpenResty में, आपngx.var.schemeका उपयोग करके उसी मान को वापस कर सकते हैं। $request_methodअनुरोध विधि जैसेGET,POST, आदि को दर्शाता है; OpenResty में, आपngx.var.request_methodके माध्यम से उसी मान को वापस कर सकते हैं।
आप NGINX आधिकारिक दस्तावेज़ पर जाकर NGINX बिल्ट-इन वेरिएबल्स की पूरी सूची प्राप्त कर सकते हैं: http://nginx.org/en/docs/http/ngx_http_core_module.html#variables.
तो सवाल उठता है: जब आप ngx.var.* जैसे वेरिएबल के मान को वापस करके अनुरोध लाइन में डेटा प्राप्त कर सकते हैं, तो OpenResty अनुरोध लाइन के लिए एक अलग API क्यों प्रदान करता है?
इसके परिणाम में कई कारक शामिल हैं:
- सबसे पहले,
ngx.varको बार-बार पढ़ने की सिफारिश नहीं की जाती है क्योंकि इसकी प्रदर्शन क्षमता कम होती है। - दूसरा, प्रोग्राम-अनुकूल पहलू को ध्यान में रखते हुए,
ngx.varएक स्ट्रिंग वापस करता है, न कि एक Lua ऑब्जेक्ट। जबargsप्राप्त करते हैं, जो कई मान वापस कर सकता है, तो इसे संभालना मुश्किल होता है। - तीसरा, लचीलेपन के पहलू से,
ngx.varका अधिकांश भाग केवल पढ़ने योग्य होता है, और केवल कुछ वेरिएबल्स लिखने योग्य होते हैं, जैसे$argsऔरlimit_rate। हालांकि, हमें अक्सर विधि, URI, और args को संशोधित करने की आवश्यकता होती है।
इसलिए, OpenResty अनुरोध लाइन को संशोधित करने के लिए कई API प्रदान करता है, जो अनुरोध लाइन को पुनः लिख सकते हैं ताकि पुनर्निर्देशन जैसे बाद के ऑपरेशन किए जा सकें।
आइए देखें कि API के माध्यम से HTTP प्रोटोकॉल संस्करण संख्या कैसे प्राप्त करें। OpenResty API ngx.req.http_version NGINX $server_protocol वेरिएबल के समान कार्य करता है: HTTP प्रोटोकॉल का संस्करण संख्या वापस करना। हालांकि, इस API का रिटर्न वैल्यू एक स्ट्रिंग नहीं है बल्कि संख्यात्मक प्रारूप में है, जिसके संभावित मान 2.0, 1.0, 1.1, और 0.9 हैं। यदि परिणाम इन मानों की सीमा से बाहर है तो Nil वापस आता है।
आइए अनुरोध लाइन में अनुरोध विधि प्राप्त करने की विधि देखें। जैसा कि उल्लेख किया गया है, ngx.req.get_method और NGINX के $request_method वेरिएबल्स की भूमिका और रिटर्न वैल्यू समान हैं: स्ट्रिंग प्रारूप में।
हालांकि, वर्तमान HTTP अनुरोध विधि ngx.req.set_method का पैरामीटर प्रारूप एक स्ट्रिंग नहीं है बल्कि बिल्ट-इन संख्यात्मक स्थिरांक है। उदाहरण के लिए, निम्नलिखित कोड अनुरोध विधि को POST में बदल देता है।
ngx.req.set_method(ngx.HTTP_POST)
यह सत्यापित करने के लिए कि बिल्ट-इन स्थिरांक, ngx.HTTP_POST वास्तव में एक संख्या है और स्ट्रिंग नहीं है, आप इसका मान प्रिंट कर सकते हैं और देख सकते हैं कि आउटपुट 8 है या नहीं।
resty -e 'print(ngx.HTTP_POST)'
इस तरह, get विधि का रिटर्न वैल्यू एक स्ट्रिंग है, जबकि set विधि का इनपुट वैल्यू एक संख्या है। यह ठीक है जब सेट विधि एक भ्रमित करने वाला मान पास करती है क्योंकि API क्रैश हो सकता है और 500 त्रुटि के साथ रिपोर्ट कर सकता है। हालांकि, निम्नलिखित निर्णय लॉजिक में:
if (ngx.req.get_method() == ngx.HTTP_POST) then -- कुछ करें end
इस तरह का कोड ठीक काम करता है, कोई त्रुटि रिपोर्ट नहीं करता है, और कोड समीक्षा के दौरान भी इसे ढूंढना मुश्किल होता है। मैंने पहले एक समान गलती की थी और अभी भी इसे याद कर सकता हूं: मैंने पहले ही दो राउंड की कोड समीक्षा और अधूरे टेस्ट केस को कवर करने की कोशिश की थी। अंत में, एक ऑनलाइन वातावरण में असामान्यता ने मुझे समस्या का पता लगाया।
ऐसी समस्या को हल करने के लिए कोई व्यावहारिक तरीका नहीं है सिवाय इसके कि अधिक सावधान रहें या एक और परत जोड़ें। जब आप अपने व्यवसाय API को डिज़ाइन करते हैं, तो आप get और set विधियों के सुसंगत पैरामीटर प्रारूप को भी ध्यान में रख सकते हैं, भले ही आपको कुछ प्रदर्शन का त्याग करना पड़े।
इसके अलावा, अनुरोध लाइन को पुनः लिखने की विधियों में, ngx.req.set_uri और ngx.req.set_uri_args दो API हैं, जिनका उपयोग URI और args को पुनः लिखने के लिए किया जा सकता है। आइए इस NGINX कॉन्फ़िगरेशन को देखें।
rewrite ^ /foo?a=3? break;
तो, हम इसे समकक्ष Lua API के साथ कैसे हल कर सकते हैं? उत्तर निम्नलिखित दो लाइनों का कोड है।
ngx.req.set_uri_args("a=3") ngx.req.set_uri("/foo")
यदि आपने आधिकारिक दस्तावेज़ पढ़ा है, तो आप पाएंगे कि ngx.req.set_uri का दूसरा पैरामीटर: jump, जो डिफ़ॉल्ट रूप से "false" है। यदि आप इसे "true" के रूप में सेट करते हैं, तो यह rewrite कमांड के फ्लैग को last के बजाय break के रूप में सेट करने के बराबर है, जैसा कि ऊपर के उदाहरण में है।
हालांकि, मुझे rewrite कमांड के फ्लैग कॉन्फ़िगरेशन पसंद नहीं है क्योंकि यह अप्राप्य और अज्ञात है और कोड की तुलना में कम सहज और रखरखाव योग्य है।
अनुरोध हेडर
जैसा कि हम जानते हैं, HTTP अनुरोध हेडर key : value प्रारूप में होते हैं, उदाहरण के लिए:
Accept: text/css,*/*;q=0.1 Accept-Encoding: gzip, deflate, br
OpenResty में, आप ngx.req.get_headers का उपयोग करके अनुरोध हेडर को पार्स और प्राप्त कर सकते हैं, और रिटर्न वैल्यू प्रकार टेबल है।
local h, err = ngx.req.get_headers() if err == "truncated" then -- कोई यहां वर्तमान अनुरोध को अनदेखा या अस्वीकार करने का विकल्प चुन सकता है end for k, v in pairs(h) do ... end
यह डिफ़ॉल्ट रूप से पहले 100 हेडर वापस करता है। यदि संख्या 100 से अधिक है, तो यह एक truncated त्रुटि रिपोर्ट करेगा, जिसे डेवलपर को यह तय करने के लिए छोड़ दिया जाता है कि इसे कैसे संभाला जाए। आप सोच सकते हैं कि इसे इस तरह क्यों लिया गया है, जिसका उल्लेख मैं बाद में सुरक्षा कमजोरियों के अनुभाग में करूंगा।
हालांकि, हमें ध्यान देना चाहिए कि OpenResty किसी विशिष्ट अनुरोध हेडर को प्राप्त करने के लिए कोई विशिष्ट API प्रदान नहीं करता है, जिसका अर्थ है कि ngx.req.header['host'] जैसा कोई रूप नहीं है। यदि आपके पास ऐसी आवश्यकता है, तो आपको NGINX वेरिएबल $http_xxx पर निर्भर रहना होगा। फिर OpenResty में, आप इसे ngx.var.http_xxx के माध्यम से प्राप्त कर सकते हैं।
अब आइए देखें कि हमें अनुरोध हेडर को पुनः लिखने और हटाने के लिए कैसे करना चाहिए। दोनों ऑपरेशन के लिए API काफी सहज हैं:
ngx.req.set_header("Content-Type", "text/css") ngx.req.clear_header("Content-Type")
बेशक, आधिकारिक दस्तावेज़ में अनुरोध हेडर को हटाने के अन्य तरीकों का भी उल्लेख किया गया है, जैसे कि शीर्षक के मान को nil पर सेट करना, आदि। हालांकि, मैं अभी भी कोड की स्पष्टता के लिए clear_header का उपयोग करने की सिफारिश करता हूं।
अनुरोध बॉडी
अंत में, आइए अनुरोध बॉडी को देखें। प्रदर्शन कारणों से, OpenResty सक्रिय रूप से अनुरोध बॉडी को नहीं पढ़ता है जब तक कि आप nginx.conf में lua_need_request_body निर्देश को सक्षम नहीं करते हैं। इसके अलावा, बड़े अनुरोध बॉडी के लिए, OpenResty सामग्री को डिस्क पर एक अस्थायी फ़ाइल में सहेजता है, इसलिए अनुरोध बॉडी को पढ़ने की पूरी प्रक्रिया इस तरह दिखती है।
ngx.req.read_body() local data = ngx.req.get_body_data() if not data then local tmp_file = ngx.req.get_body_file() -- io.open(tmp_file) -- ... end
इस कोड में डिस्क फ़ाइल को पढ़ने के लिए एक IO-ब्लॉकिंग ऑपरेशन है। आपको client_body_buffer_size (64-बिट सिस्टम पर डिफ़ॉल्ट रूप से 16 KB) के कॉन्फ़िगरेशन को समायोजित करना चाहिए ताकि ब्लॉकिंग ऑपरेशन को कम से कम किया जा सके; आप client_body_buffer_size और client_max_body_size को समान रूप से कॉन्फ़िगर कर सकते हैं और उन्हें पूरी तरह से मेमोरी में संभाल सकते हैं, यह आपकी मेमोरी के आकार और आपके द्वारा लिए जाने वाले समवर्ती अनुरोधों की संख्या पर निर्भर करता है।
इसके अलावा, अनुरोध बॉडी को पुनः लिखा जा सकता है। दो API ngx.req.set_body_data और ngx.req.set_body_file एक स्ट्रिंग और एक स्थानीय डिस्क फ़ाइल को इनपुट पैरामीटर के रूप में स्वीकार करते हैं ताकि अनुरोध बॉडी को पुनः लिखा जा सके। हालांकि, इस प्रकार का ऑपरेशन असामान्य है, और आप अधिक विवरण के लिए दस्तावेज़ देख सकते हैं।
प्रतिक्रिया
अनुरोध के प्रसंस्करण के बाद, हमें क्लाइंट को एक प्रतिक्रिया भेजने की आवश्यकता होती है। अनुरोध संदेश की तरह, प्रतिक्रिया संदेश भी कई भागों से बना होता है: स्थिति लाइन, प्रतिक्रिया हेडर, और प्रतिक्रिया बॉडी। मैं इन तीन भागों के अनुसार संबंधित API का परिचय दूंगा।
स्थिति लाइन
स्थिति लाइन में हम मुख्य रूप से स्थिति कोड के बारे में चिंतित हैं। डिफ़ॉल्ट रूप से, वापस आने वाला HTTP स्थिति कोड 200 है, जो OpenResty में बिल्ट-इन स्थिरांक ngx.HTTP_OK है। लेकिन कोड की दुनिया में, हमेशा सबसे असाधारण मामलों को संभालने वाला कोड होता है।
यदि आप अनुरोध संदेश का पता लगाते हैं और पाते हैं कि यह एक दुर्भावनापूर्ण अनुरोध है, तो आपको अनुरोध को समाप्त करने की आवश्यकता है:
ngx.exit(ngx.HTTP_BAD_REQUEST)
हालांकि, OpenResty के HTTP स्थिति कोड में एक विशेष स्थिरांक है: ngx.OK। ngx.exit(ngx.OK) की स्थिति में, अनुरोध वर्तमान प्रसंस्करण चरण से बाहर निकलता है और अगले चरण में चला जाता है, न कि सीधे क्लाइंट को वापस आता है।
बेशक, आप बाहर निकलने का विकल्प नहीं चुन सकते हैं और केवल स्थिति कोड को ngx.status का उपयोग करके पुनः लिख सकते हैं, जैसा कि निम्नलिखित तरीके से लिखा गया है।
ngx.status = ngx.HTTP_FORBIDDEN
यदि आप स्थिति कोड स्थिरांक के बारे में अधिक जानना चाहते हैं, तो आप दस्तावेज़ में उन्हें देख सकते हैं।
प्रतिक्रिया हेडर
प्रतिक्रिया हेडर के संबंध में, आप इसे दो तरीकों से सेट कर सकते हैं। पहला तरीका सबसे सरल है।
ngx.header.content_type = 'text/plain' ngx.header["X-My-Header"] = 'blah blah' ngx.header["X-My-Header"] = nil -- हटाएं
यहां ngx.header प्रतिक्रिया हेडर जानकारी को रखता है, जिसे पढ़ा, संशोधित और हटाया जा सकता है।
प्रतिक्रिया हेडर सेट करने का दूसरा तरीका ngx_resp.add_header है, जो lua-resty-core रिपॉजिटरी से है, जो एक हेडर संदेश जोड़ता है, जिसे इस तरह कॉल किया जाता है:
local ngx_resp = require "ngx.resp" ngx_resp.add_header("Foo", "bar")
पहले तरीके के साथ अंतर यह है कि add_header मौजूदा समान नाम के फ़ील्ड को ओवरराइट नहीं करता है।
प्रतिक्रिया बॉडी
अंत में, प्रतिक्रिया बॉडी को देखें। OpenResty में, आप ngx.say और ngx.print का उपयोग करके प्रतिक्रिया बॉडी को आउटपुट कर सकते हैं।
ngx.say('hello, world')
दोनों API की कार्यक्षमता समान है, केवल अंतर यह है कि ngx.say के अंत में एक लाइन फ़ीड होता है।
स्ट्रिंग जोड़ने की अक्षमता से बचने के लिए, ngx.say / ngx.print स्ट्रिंग और सरणी प्रारूप को पैरामीटर के रूप में समर्थन करता है।
$ resty -e 'ngx.say({"hello", ", ", "world"})' hello, world
यह विधि Lua स्तर पर स्ट्रिंग जोड़ने को छोड़ देती है और इसे C फ़ंक्शन को संभालने के लिए छोड़ देती है।
सारांश
आइए आज की सामग्री की समीक्षा करें। हमने अनुरोध और प्रतिक्रिया संदेशों से संबंधित OpenResty API का परिचय दिया। जैसा कि आप देख सकते हैं, OpenResty API NGINX निर्देश से अधिक लचीला और शक्तिशाली है।
नतीजतन, क्या OpenResty द्वारा प्रदान किया गया Lua API आपकी आवश्यकताओं को पूरा करने के लिए पर्याप्त है जब आप HTTP अनुरोधों को संभाल रहे हैं? कृपया अपनी टिप्पणियाँ छोड़ें और इस लेख को अपने सहयोगियों और दोस्तों के साथ साझा करें ताकि हम एक साथ संवाद और सुधार कर सकें।