ngx_http_lua_module - تضمين قوة Lua في خوادم Nginx HTTP.
هذه الوحدة هي أحد المكونات الأساسية لـ OpenResty. إذا كنت تستخدم هذه الوحدة، فأنت تستخدم OpenResty بشكل أساسي :)
لا يتم توزيع هذه الوحدة مع مصدر Nginx. راجع تعليمات التثبيت.
الإنتاج جاهز.
يصف هذا المستند ngx_lua v0.10.25، الذي تم إصداره في 19 يونيو 2023.
مقطع فيديو على YouTube "مثال لـ Hello World HTTP مع OpenResty/Lua"
فيديو YouTube "اكتب وحدات Lua الخاصة بك في تطبيقات OpenResty/Nginx"
مقطع فيديو على YouTube "العرض التوضيحي لأداة سطر الأوامر المريحة لـ OpenResty"
فيديو على YouTube "قياس وقت تنفيذ كود Lua بشكل صحيح في OpenResty"
فيديو YouTube "ترجمة وحدات Lua مسبقًا إلى LuaJIT Bytecode لتسريع بدء تشغيل OpenResty"
نرحب باشتراكك في قناتنا الرسمية على YouTube، OpenResty.
العودة إلى جدول المحتويات
# set search paths for pure Lua external libraries (';;' is the default path):
lua_package_path '/foo/bar/?.lua;/blah/?.lua;;' ;
# set search paths for Lua external libraries written in C (can also use ';;'):
lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;' ;
server {
location /lua_content {
# MIME type determined by default_type:
default_type 'text/plain' ;
content_by_lua_block {
ngx.say('Hello,world!')
}
}
location /nginx_var {
# MIME type determined by default_type:
default_type 'text/plain' ;
# try access /nginx_var?a=hello,world
content_by_lua_block {
ngx.say(ngx.var.arg_a)
}
}
location = /request_body {
client_max_body_size 50k ;
client_body_buffer_size 50k ;
content_by_lua_block {
ngx.req.read_body() -- explicitly read the req body
local data = ngx.req.get_body_data()
if data then
ngx.say(" body data: ")
ngx.print(data)
return
end
-- body may get buffered in a temp file:
local file = ngx.req.get_body_file()
if file then
ngx.say(" body is in file ", file)
else
ngx.say(" no body found ")
end
}
}
# transparent non-blocking I/O in Lua via subrequests
# (well, a better way is to use cosockets)
location = /lua {
# MIME type determined by default_type:
default_type 'text/plain';
content_by_lua_block {
local res = ngx.location.capture(" /some_other_location ")
if res then
ngx.say(" status: ", res.status)
ngx.say(" body: ")
ngx.print(res.body)
end
}
}
location = /foo {
rewrite_by_lua_block {
res = ngx.location.capture(" /memc ",
{ args = { cmd = " incr ", key = ngx.var.uri } }
)
}
proxy_pass http://blah.blah.com;
}
location = /mixed {
rewrite_by_lua_file /path/to/rewrite.lua;
access_by_lua_file /path/to/access.lua;
content_by_lua_file /path/to/content.lua;
}
# use nginx var in code path
# CAUTION: contents in nginx var must be carefully filtered,
# otherwise there'll be great security risk!
location ~ ^/app/([-_a-zA-Z0-9/]+) {
set $path $1 ;
content_by_lua_file /path/to/lua/app/root/ $path .lua;
}
location / {
client_max_body_size 100k;
client_body_buffer_size 100k;
access_by_lua_block {
-- check the client IP address is in our black list
if ngx.var.remote_addr == " 132.5.72.3 " then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
-- check if the URI contains bad words
if ngx.var.uri and
string.match(ngx.var.request_body, " evil ")
then
return ngx.redirect(" /terms_of_use.html ")
end
-- tests passed
}
# proxy_pass/fastcgi_pass/etc settings
}
}
العودة إلى جدول المحتويات
تقوم هذه الوحدة بتضمين LuaJIT 2.0/2.1 في Nginx. وهو مكون أساسي في OpenResty. إذا كنت تستخدم هذه الوحدة، فأنت تستخدم OpenResty بشكل أساسي.
منذ الإصدار v0.10.16
من هذه الوحدة، لم يعد مترجم Lua القياسي (المعروف أيضًا باسم "PUC-Rio Lua") مدعومًا بعد الآن. تستخدم هذه الوثيقة المصطلحين "Lua" و"LuaJIT" بالتبادل للإشارة إلى مترجم LuaJIT.
من خلال الاستفادة من طلبات Nginx الفرعية، تتيح هذه الوحدة دمج سلاسل Lua القوية (المعروفة باسم "coroutines" Lua) في نموذج حدث Nginx.
على عكس mod_lua الخاص بـ Apache وmod_magnet الخاص بـ Lighttpd، يمكن أن يكون كود Lua الذي يتم تنفيذه باستخدام هذه الوحدة غير محظور بنسبة 100% على حركة مرور الشبكة طالما أن واجهة برمجة تطبيقات Nginx لـ Lua التي توفرها هذه الوحدة تُستخدم للتعامل مع طلبات الخدمات الأولية مثل MySQL وPostgreSQL وMemcached أو Redis أو خدمات ويب HTTP الأولية.
يمكن استخدام مكتبات Lua ووحدات Nginx التالية على الأقل مع هذه الوحدة:
يمكن استخدام أي وحدات Nginx تقريبًا مع وحدة ngx_lua هذه عن طريق ngx.location.capture أو ngx.location.capture_multi ولكن يوصى باستخدام مكتبات lua-resty-*
تلك بدلاً من إنشاء طلبات فرعية للوصول إلى وحدات Nginx الأولية لأن عادةً ما يكون الأول أكثر مرونة وكفاءة في الذاكرة.
تتم مشاركة مترجم Lua (المعروف أيضًا باسم "Lua State" أو "LuaJIT VM") عبر جميع الطلبات في عملية عاملة واحدة لـ Nginx لتقليل استخدام الذاكرة. يتم فصل سياقات الطلب باستخدام كوروتينات Lua خفيفة الوزن.
تستمر وحدات Lua المحملة في مستوى العملية المنفذة لـ Nginx مما يؤدي إلى بصمة ذاكرة صغيرة في Lua حتى عندما تكون تحت أحمال ثقيلة.
تم توصيل هذه الوحدة بالنظام الفرعي "http" الخاص بـ Nginx بحيث يمكنها فقط التحدث ببروتوكولات الاتصال النهائية في عائلة HTTP (HTTP 0.9/1.0/1.1/2.0، WebSockets، إلخ...). إذا كنت تريد إجراء اتصالات TCP عامة مع عملاء المصب، فيجب عليك استخدام وحدة ngx_stream_lua بدلاً من ذلك، والتي توفر واجهة برمجة التطبيقات Lua API المتوافقة.
العودة إلى جدول المحتويات
على سبيل المثال لا الحصر:
الإمكانيات غير محدودة لأن الوحدة تسمح بجمع عناصر مختلفة داخل Nginx بالإضافة إلى كشف قوة لغة Lua للمستخدم. توفر الوحدة مرونة كاملة في البرمجة النصية مع تقديم مستويات أداء قابلة للمقارنة مع برامج لغة C الأصلية من حيث وقت وحدة المعالجة المركزية بالإضافة إلى مساحة الذاكرة بفضل LuaJIT 2.x.
عادةً ما تكافح تطبيقات لغة البرمجة النصية الأخرى لمطابقة مستوى الأداء هذا.
العودة إلى جدول المحتويات
أحدث إصدار من هذه الوحدة متوافق مع الإصدارات التالية من Nginx:
نوى Nginx الأقدم من 1.6.0 (حصريًا) غير مدعومة.
العودة إلى جدول المحتويات
يُنصح بشدة باستخدام إصدارات OpenResty التي تتضمن Nginx وngx_lua (هذه الوحدة) وLuaJIT، بالإضافة إلى وحدات Nginx المصاحبة القوية الأخرى ومكتبات Lua.
لا يُنصح ببناء هذه الوحدة باستخدام Nginx بنفسك نظرًا لصعوبة إعدادها بشكل صحيح.
لاحظ أن الإصدارات الرسمية من Nginx وLuaJIT وOpenSSL بها قيود متعددة وأخطاء طويلة الأمد يمكن أن تتسبب في تعطيل بعض ميزات هذه الوحدة، أو عدم العمل بشكل صحيح، أو تشغيلها بشكل أبطأ. يوصى بإصدارات OpenResty الرسمية لأنها تحتوي على شوكة LuaJIT 2.1 المحسنة من OpenResty وتصحيحات Nginx/OpenSSL.
بدلًا من ذلك، يمكن تجميع ngx_lua يدويًا في Nginx:
قم ببناء المصدر باستخدام هذه الوحدة:
wget ' https://openresty.org/download/nginx-1.19.3.tar.gz '
tar -xzvf nginx-1.19.3.tar.gz
cd nginx-1.19.3/
# tell nginx's build system where to find LuaJIT 2.0:
export LUAJIT_LIB=/path/to/luajit/lib
export LUAJIT_INC=/path/to/luajit/include/luajit-2.0
# tell nginx's build system where to find LuaJIT 2.1:
export LUAJIT_LIB=/path/to/luajit/lib
export LUAJIT_INC=/path/to/luajit/include/luajit-2.1
# Here we assume Nginx is to be installed under /opt/nginx/.
./configure --prefix=/opt/nginx
--with-ld-opt= " -Wl,-rpath,/path/to/luajit/lib "
--add-module=/path/to/ngx_devel_kit
--add-module=/path/to/lua-nginx-module
# Note that you may also want to add `./configure` options which are used in your
# current nginx build.
# You can get usually those options using command nginx -V
# you can change the parallelism number 2 below to fit the number of spare CPU cores in your
# machine.
make -j2
make install
# Note that this version of lug-nginx-module not allow to set `lua_load_resty_core off;` any more.
# So, you have to install `lua-resty-core` and `lua-resty-lrucache` manually as below.
cd lua-resty-core
make install PREFIX=/opt/nginx
cd lua-resty-lrucache
make install PREFIX=/opt/nginx
# add necessary `lua_package_path` directive to `nginx.conf`, in the http context
lua_package_path " /opt/nginx/lib/lua/?.lua;; " ;
العودة إلى جدول المحتويات
بدءًا من NGINX 1.9.11، يمكنك أيضًا تجميع هذه الوحدة كوحدة ديناميكية، باستخدام خيار --add-dynamic-module=PATH
بدلاً من --add-module=PATH
في سطر الأوامر ./configure
أعلاه. ومن ثم يمكنك تحميل الوحدة بشكل صريح في nginx.conf
عبر التوجيه Load_module، على سبيل المثال،
load_module /path/to/modules/ndk_http_module.so; # assuming NDK is built as a dynamic module too
load_module /path/to/modules/ngx_http_lua_module.so;
العودة إلى جدول المحتويات
أثناء بناء هذه الوحدة إما عبر OpenResty أو باستخدام نواة Nginx، يمكنك تحديد وحدات ماكرو C التالية عبر خيارات مترجم C:
NGX_LUA_USE_ASSERT
عند تعريفه، سيتم تمكين التأكيدات في قاعدة كود ngx_lua C. يوصى به لتصحيح الأخطاء أو بنيات الاختبار. يمكن أن يقدم بعض النفقات العامة (الصغيرة) لوقت التشغيل عند تمكينها. تم تقديم هذا الماكرو لأول مرة في الإصدار v0.9.10
.NGX_LUA_ABORT_AT_PANIC
عندما يصاب جهاز LuaJIT VM بالذعر، سيوجه ngx_lua عملية تنفيذ nginx الحالية للإنهاء بأمان بشكل افتراضي. من خلال تحديد ماكرو C هذا، سيقوم ngx_lua بإحباط العملية المنفذة الحالية لـ nginx (والتي عادةً ما تؤدي إلى ملف تفريغ أساسي) على الفور. يعد هذا الخيار مفيدًا لتصحيح أخطاء الذعر VM. تم تقديم هذا الخيار لأول مرة في الإصدار v0.9.8
. لتمكين واحد أو أكثر من وحدات الماكرو هذه، ما عليك سوى تمرير خيارات مترجم C الإضافية إلى البرنامج النصي ./configure
الخاص بـ Nginx أو OpenResty. على سبيل المثال،
./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC"
العودة إلى جدول المحتويات
العودة إلى جدول المحتويات
القائمة البريدية openresty-en مخصصة للمتحدثين باللغة الإنجليزية.
العودة إلى جدول المحتويات
القائمة البريدية المفتوحة مخصصة للمتحدثين باللغة الصينية.
العودة إلى جدول المحتويات
تتم استضافة مستودع التعليمات البرمجية لهذا المشروع على GitHub في openresty/lua-nginx-module.
العودة إلى جدول المحتويات
يرجى إرسال تقارير الأخطاء أو قوائم الرغبات أو التصحيحات بواسطة
العودة إلى جدول المحتويات
شاهد فيديو YouTube "قياس وقت تنفيذ كود Lua بشكل صحيح في OpenResty"
اعتبارًا من الإصدار v0.5.0rc32
، تدعم جميع توجيهات تكوين *_by_lua_file
(مثل content_by_lua_file) تحميل ملفات الكود الثانوي LuaJIT 2.0/2.1 مباشرةً:
/path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc
يمكن استخدام الخيار -bg
لتضمين معلومات التصحيح في ملف LuaJIT bytecode:
/path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc
يرجى الرجوع إلى وثائق LuaJIT الرسمية حول الخيار -b
لمزيد من التفاصيل:
https://luajit.org/running.html#opt_b
لاحظ أن ملفات الرمز الثانوي التي تم إنشاؤها بواسطة LuaJIT 2.1 غير متوافقة مع LuaJIT 2.0، والعكس صحيح. تمت إضافة دعم الكود الثانوي LuaJIT 2.1 لأول مرة في ngx_lua v0.9.3.
ستؤدي محاولات تحميل ملفات Lua 5.1 bytecode القياسية إلى مثيلات ngx_lua المرتبطة بـ LuaJIT 2.0/2.1 (أو العكس) إلى ظهور رسالة خطأ Nginx مثل تلك الموجودة أدناه:
[error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac
يجب أن يعمل تحميل ملفات bytecode عبر عناصر Lua الأولية مثل require
و dofile
دائمًا كما هو متوقع.
العودة إلى جدول المحتويات
إذا كنت تريد الوصول إلى متغير بيئة النظام، على سبيل المثال، foo
، في Lua عبر واجهة Lua API القياسية os.getenv، فيجب عليك أيضًا إدراج اسم متغير البيئة هذا في ملف nginx.conf
عبر توجيه env. على سبيل المثال،
env foo;
العودة إلى جدول المحتويات
لا يدعم بروتوكول HTTP 1.0 الإخراج المقسم ويتطلب رأسًا صريحًا Content-Length
عندما لا يكون نص الاستجابة فارغًا لدعم استمرار HTTP 1.0. لذا، عند إجراء طلب HTTP 1.0 on
التوجيه lua_http10_buffering، سيقوم ngx_lua بتخزين مخرجات مكالمات ngx.say وngx.print وكذلك تأجيل إرسال رؤوس الاستجابة حتى يتم استلام جميع مخرجات نص الاستجابة. في ذلك الوقت، يمكن لـ ngx_lua حساب الطول الإجمالي للنص وإنشاء رأس مناسب Content-Length
للعودة إلى عميل HTTP 1.0. إذا تم تعيين رأس استجابة Content-Length
في كود Lua قيد التشغيل، فسيتم تعطيل هذا التخزين المؤقت حتى إذا تم on
التوجيه lua_http10_buffering .
بالنسبة لاستجابات مخرجات البث الكبيرة، من المهم تعطيل التوجيه lua_http10_buffering لتقليل استخدام الذاكرة.
لاحظ أن أدوات قياس أداء HTTP الشائعة، مثل ab
و http_load
تصدر طلبات HTTP 1.0 بشكل افتراضي. لإجبار curl
على إرسال طلبات HTTP 1.0، استخدم الخيار -0
.
العودة إلى جدول المحتويات
باستخدام LuaJIT 2.x، من الممكن ربط الكود الثانوي لوحدات Lua النقية بشكل ثابت بملف Nginx القابل للتنفيذ.
يمكنك استخدام الملف luajit
القابل للتنفيذ لتجميع ملفات وحدة .lua
Lua إلى ملفات كائن .o
التي تحتوي على بيانات البايت كود المصدرة، ثم ربط ملفات .o
مباشرة في بناء Nginx الخاص بك.
فيما يلي مثال تافه لإثبات ذلك. ضع في اعتبارك أن لدينا ملف .lua
التالي المسمى foo.lua
:
-- foo.lua
local _M = {}
function _M . go ()
print ( " Hello from foo " )
end
return _M
ثم نقوم بتجميع ملف .lua
هذا إلى ملف foo.o
:
/path/to/luajit/bin/luajit -bg foo.lua foo.o
ما يهم هنا هو اسم الملف .lua
، الذي يحدد كيفية استخدام هذه الوحدة لاحقًا على أرض Lua. لا يهم اسم الملف foo.o
على الإطلاق باستثناء امتداد الملف .o
(الذي يخبر luajit
بتنسيق الإخراج المستخدم). إذا كنت تريد تجريد معلومات تصحيح أخطاء Lua من الكود الثانوي الناتج، فيمكنك فقط تحديد الخيار -b
أعلاه بدلاً من -bg
.
ثم عند إنشاء Nginx أو OpenResty، قم بتمرير خيار --with-ld-opt="foo.o"
إلى البرنامج النصي ./configure
:
./configure --with-ld-opt= " /path/to/foo.o " ...
أخيرًا، يمكنك فقط القيام بما يلي في أي كود Lua يتم تشغيله بواسطة ngx_lua:
local foo = require " foo "
foo . go ()
ولم يعد هذا الجزء من التعليمات البرمجية يعتمد على ملف foo.lua
الخارجي بعد الآن لأنه تم تجميعه بالفعل في ملف nginx
القابل للتنفيذ.
إذا كنت تريد استخدام النقطة في اسم وحدة Lua عند الاتصال، كما هو require
في
local foo = require " resty.foo "
فأنت بحاجة إلى إعادة تسمية الملف foo.lua
إلى resty_foo.lua
قبل تجميعه إلى ملف .o
باستخدام الأداة المساعدة لسطر الأوامر luajit
.
من المهم استخدام نفس الإصدار تمامًا من LuaJIT عند تجميع ملفات .lua
إلى ملفات .o
مثل إنشاء nginx + ngx_lua. وذلك لأن تنسيق LuaJIT bytecode قد يكون غير متوافق بين إصدارات LuaJIT المختلفة. عندما يكون تنسيق الرمز الثانوي غير متوافق، سترى خطأ وقت تشغيل Lua يشير إلى عدم العثور على وحدة Lua.
عندما يكون لديك ملفات .lua
متعددة لتجميعها وربطها، فما عليك سوى تحديد ملفات .o
الخاصة بها في نفس الوقت بقيمة خيار --with-ld-opt
. على سبيل المثال،
./configure --with-ld-opt= " /path/to/foo.o /path/to/bar.o " ...
إذا كان لديك عدد كبير جدًا من ملفات .o
، فقد لا يكون من الممكن تسمية كل هذه الملفات في أمر واحد. في هذه الحالة، يمكنك إنشاء مكتبة ثابتة (أو أرشيف) لملفاتك .o
، كما في
ar rcus libmyluafiles.a * .o
ثم يمكنك ربط أرشيف myluafiles
ككل بملف nginx القابل للتنفيذ:
./configure
--with-ld-opt= " -L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive "
حيث /path/to/lib
هو مسار الدليل الذي يحتوي على الملف libmyluafiles.a
. تجدر الإشارة إلى أن خيار الرابط --whole-archive
مطلوب هنا وإلا فسيتم تخطي أرشيفنا لأنه لم يتم ذكر أي رموز في أرشيفنا في الأجزاء الرئيسية من ملف nginx القابل للتنفيذ.
العودة إلى جدول المحتويات
لمشاركة البيانات عالميًا بين جميع الطلبات التي تتم معالجتها بواسطة نفس العملية المنفذة لـ Nginx، قم بتغليف البيانات المشتركة في وحدة Lua، واستخدم Lua require
المدمج لاستيراد الوحدة، ثم معالجة البيانات المشتركة في Lua. يعمل هذا لأنه يتم تحميل وحدات Lua المطلوبة مرة واحدة فقط وستشارك جميع coroutines نفس النسخة من الوحدة (كلا من الكود والبيانات).
لاحظ أنه لا يُنصح بشدة باستخدام متغيرات Lua العامة، لأنها قد تؤدي إلى حالات سباق غير متوقعة بين الطلبات المتزامنة.
فيما يلي مثال صغير على مشاركة البيانات داخل عامل Nginx عبر وحدة Lua:
-- mydata.lua
local _M = {}
local data = {
dog = 3 ,
cat = 4 ,
pig = 5 ,
}
function _M . get_age ( name )
return data [ name ]
end
return _M
ثم الوصول إليه من nginx.conf
:
location /lua {
content_by_lua_block {
local mydata = require "mydata"
ngx.say(mydata.get_age("dog"))
}
}
سيتم تحميل وحدة mydata
في هذا المثال وتشغيلها فقط عند الطلب الأول إلى الموقع /lua
، وستستخدم جميع الطلبات اللاحقة لنفس العملية المنفذة في Nginx المثيل المُعاد تحميله للوحدة بالإضافة إلى نفس نسخة البيانات الموجودة في حتى يتم إرسال إشارة HUP
إلى عملية Nginx الرئيسية لفرض إعادة التحميل. تعد تقنية مشاركة البيانات هذه ضرورية لتطبيقات Lua عالية الأداء بناءً على هذه الوحدة.
لاحظ أن مشاركة البيانات هذه تتم على أساس كل عامل وليس على أساس كل خادم . أي أنه عندما يكون هناك العديد من العمليات المنفذة لـ Nginx ضمن Nginx الرئيسي، لا يمكن لمشاركة البيانات عبور حدود العملية بين هؤلاء العاملين.
يوصى عادةً بمشاركة البيانات للقراءة فقط بهذه الطريقة. يمكنك أيضًا مشاركة البيانات القابلة للتغيير بين جميع الطلبات المتزامنة لكل عملية عاملة في Nginx طالما لا توجد عمليات إدخال/إخراج غير محظورة (بما في ذلك ngx.sleep) في منتصف حساباتك. طالما أنك لا تعيد التحكم إلى حلقة أحداث Nginx ومجدول سلاسل الرسائل الخفيفة الخاص بـ ngx_lua (حتى بشكل ضمني)، فلن يكون هناك أي شروط سباق بينهما. لهذا السبب، كن حذرًا جدًا دائمًا عندما تريد مشاركة البيانات القابلة للتغيير على مستوى العامل. يمكن أن تؤدي تحسينات الأخطاء بسهولة إلى ظروف سباق يصعب تصحيحها تحت الحمل.
إذا كانت مشاركة البيانات على مستوى الخادم مطلوبة، فاستخدم واحدًا أو أكثر من الأساليب التالية:
memcached
أو redis
أو MySQL
أو PostgreSQL
. تأتي إصدارات OpenResty الرسمية مع مجموعة من وحدات Nginx المصاحبة ومكتبات Lua التي توفر واجهات مع آليات تخزين البيانات هذه.العودة إلى جدول المحتويات
العودة إلى جدول المحتويات
قد تشير طريقة tcpsock:connect success
على الرغم من فشل الاتصال كما هو الحال مع أخطاء Connection Refused
.
ومع ذلك، ستفشل المحاولات اللاحقة لمعالجة كائن cosocket وستُرجع رسالة حالة الخطأ الفعلية التي تم إنشاؤها بواسطة عملية الاتصال الفاشلة.
ترجع هذه المشكلة إلى القيود الموجودة في نموذج حدث Nginx ويبدو أنها تؤثر فقط على نظام التشغيل Mac OS X.
العودة إلى جدول المحتويات
dofile
Lua والمكونات require
يتم تنفيذهما حاليًا كوظائف C في LuaJIT 2.0/2.1، إذا تم تحميل ملف Lua بواسطة dofile
أو require
استدعاء ngx.location.capture*، أو ngx.exec، أو ngx.exit، أو وظائف API الأخرى التي تتطلب العائد في نطاق المستوى الأعلى لملف Lua، سيتم ظهور خطأ Lua "محاولة الاستسلام عبر حدود C-call". لتجنب ذلك، ضع هذه الاستدعاءات التي تتطلب الخضوع في وظائف Lua الخاصة بك في ملف Lua بدلاً من نطاق المستوى الأعلى للملف.العودة إلى جدول المحتويات
يجب توخي الحذر عند استيراد الوحدات، ويجب استخدام هذا النموذج:
local xxx = require ( ' xxx ' )
بدلاً من النموذج القديم المهمل:
require ( ' xxx ' )
هذا هو السبب: حسب التصميم، تتمتع البيئة العالمية بنفس عمر معالج طلبات Nginx المرتبط بها. كل معالج طلب لديه مجموعته الخاصة من متغيرات Lua العالمية وهذه هي فكرة عزل الطلب. يتم تحميل وحدة Lua فعليًا بواسطة معالج طلب Nginx الأول ويتم تخزينها مؤقتًا بواسطة require()
المضمنة في جدول package.loaded
للرجوع إليها لاحقًا، كما أن module()
المضمنة المستخدمة من قبل بعض وحدات Lua لها تأثير جانبي يتمثل في الإعداد متغير عام لجدول الوحدة المحملة. ولكن سيتم مسح هذا المتغير العام في نهاية معالج الطلب، وكل معالج طلب لاحق له بيئة عالمية (نظيفة) خاصة به. لذلك سيحصل المرء على استثناء Lua للوصول إلى القيمة nil
.
يعد استخدام متغيرات Lua العامة أمرًا غير مستحسن بشكل عام في سياق ngx_lua على النحو التالي:
لذلك يوصى بشدة بالإعلان عن ذلك دائمًا ضمن نطاق محلي مناسب بدلاً من ذلك.
-- Avoid
foo = 123
-- Recommended
local foo = 123
-- Avoid
function foo () return 123 end
-- Recommended
local function foo () return 123 end
للعثور على كافة مثيلات متغيرات Lua العامة في كود Lua الخاص بك، قم بتشغيل أداة lua-releng عبر جميع ملفات مصدر .lua
:
$ lua-releng
Checking use of Lua global variables in file lib/foo/bar.lua ...
1 [1489] SETGLOBAL 7 -1 ; contains
55 [1506] GETGLOBAL 7 -3 ; setvar
3 [1545] GETGLOBAL 3 -4 ; varexpand
يقول الإخراج أن السطر 1489 من الملف lib/foo/bar.lua
يكتب إلى متغير عام يسمى contains
، ويقرأ السطر 1506 من المتغير العام setvar
، ويقرأ السطر 1545 varexpand
العمومي.
ستضمن هذه الأداة أن يتم الإعلان عن جميع المتغيرات المحلية في وظائف وحدة Lua باستخدام الكلمة الأساسية local
، وإلا سيتم طرح استثناء وقت التشغيل. يمنع ظروف السباق غير المرغوب فيها أثناء الوصول إلى مثل هذه المتغيرات. راجع مشاركة البيانات داخل عامل Nginx للتعرف على الأسباب الكامنة وراء ذلك.
العودة إلى جدول المحتويات
لا يمكن لتوجيهات ngx.location.capture وngx.location.capture_multi التقاط المواقع التي تتضمن توجيهات add_before_body، أو add_after_body، أو auth_request، أو echo_location، أو echo_location_async، أو echo_subrequest، أو echo_subrequest_async.
location /foo {
content_by_lua_block {
res = ngx.location.capture( "/bar" )
}
}
location /bar {
echo_location /blah;
}
location /blah {
echo "Success!" ;
}
$ curl -i http://example.com/foo
لن تعمل كما هو متوقع.
العودة إلى جدول المحتويات
بسبب القيود الداخلية في نواة Nginx، يتم تعطيل واجهة برمجة تطبيقات cosocket في السياقات التالية: set_by_lua*، وlog_by_lua*، وheader_filter_by_lua*، وbody_filter_by_lua.
يتم حاليًا تعطيل مجموعات cosockets أيضًا في سياقات التوجيه init_by_lua* وinit_worker_by_lua* ولكن قد نضيف دعمًا لهذه السياقات في المستقبل لأنه لا توجد قيود في نواة Nginx (أو قد يتم التغلب على هذه القيود).
ومع ذلك، يوجد حل بديل عندما لا يحتاج السياق الأصلي إلى انتظار نتائج cosocket. وهذا يعني أن إنشاء مؤقت بدون تأخير عبر واجهة برمجة التطبيقات ngx.timer.at وإجراء cosocket يؤدي إلى معالج المؤقت، الذي يعمل بشكل غير متزامن مع السياق الأصلي الذي ينشئ المؤقت.
العودة إلى جدول المحتويات
ملاحظة: بعد الإصدار v0.9.17
، يمكن تجنب هذا المأزق باستخدام توجيهات التكوين *_by_lua_block {}
.
تتطلب تسلسلات PCRE مثل d
أو s
أو w
، اهتمامًا خاصًا لأنه في السلسلة الحرفية، يتم تجريد حرف الخط المائل العكسي، ، بواسطة كل من محلل لغة Lua وبواسطة محلل ملف التكوين Nginx قبل المعالجة إذا لم يكن ضمن
*_by_lua_block {}
التوجيه. لذلك لن يعمل المقتطف التالي كما هو متوقع:
# nginx.conf
? location /test {
? content_by_lua '
? local regex = "d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE
? local m = ngx.re.match("hello, 1234", regex)
? if m then ngx.say(m[0]) else ngx.say("not matched!") end
? ' ;
? }
# evaluates to "not matched!"
لتجنب ذلك، قم بالهروب المزدوج من الشرطة المائلة العكسية:
# nginx.conf
location /test {
content_by_lua '
local regex = "\\d+"
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
' ;
}
# evaluates to "1234"
هنا، يتم تجريد \\d+
إلى \d+
بواسطة محلل ملف التكوين Nginx ويتم تجريد ذلك أيضًا إلى d+
بواسطة محلل لغة Lua قبل التشغيل.
بدلًا من ذلك، يمكن تقديم نمط regex كسلسلة حرفية من سلسلة Lua بين قوسين طويلين من خلال تغليفها بين "أقواس طويلة"، [[...]]
، وفي هذه الحالة يجب الهروب من الخطوط المائلة العكسية مرة واحدة فقط لمحلل ملف التكوين Nginx.
# nginx.conf
location /test {
content_by_lua '
local regex = [[\d+]]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
' ;
}
# evaluates to "1234"
هنا، يتم تجريد [[\d+]]
إلى [[d+]]
بواسطة محلل ملف التكوين Nginx وتتم معالجة ذلك بشكل صحيح.
لاحظ أن أطول من القوس الطويل، [=[...]=]
، قد يكون مطلوبًا إذا كان نمط التعبير العادي يحتوي على تسلسلات [...]
. يمكن استخدام النموذج [=[...]=]
كنموذج افتراضي إذا رغبت في ذلك.
# nginx.conf
location /test {
content_by_lua '
local regex = [=[[0-9]+]=]
local m = ngx.re.match("hello, 1234", regex)
if m then ngx.say(m[0]) else ngx.say("not matched!") end
' ;
}
# evaluates to "1234"
تتمثل الطريقة البديلة للهروب من تسلسلات PCRE في التأكد من وضع كود Lua في ملفات البرامج النصية الخارجية وتنفيذه باستخدام توجيهات *_by_lua_file
المتنوعة. باستخدام هذا الأسلوب، يتم تجريد الخطوط المائلة العكسية فقط بواسطة محلل لغة Lua، وبالتالي لا يلزم الهروب منها إلا مرة واحدة.
-- test.lua
local regex = " \ d+ "
local m = ngx . re . match ( " hello, 1234 " , regex )
if m then ngx . say ( m [ 0 ]) else ngx . say ( " not matched! " ) end
-- evaluates to "1234"
ضمن ملفات البرامج النصية الخارجية، لا تتطلب تسلسلات PCRE المقدمة كسلسلة حرفية طويلة Lua أي تعديل.
-- test.lua
local regex = [[ d+ ]]
local m = ngx . re . match ( " hello, 1234 " , regex )
if m then ngx . say ( m [ 0 ]) else ngx . say ( " not matched! " ) end
-- evaluates to "1234"
كما ذكرنا سابقًا، لا تتطلب تسلسلات PCRE المقدمة ضمن توجيهات *_by_lua_block {}
(المتوفرة بعد الإصدار v0.9.17
) تعديلًا.
# nginx.conf
location /test {
content_by_lua_block {
local regex = [[d+]]
local m = ngx.re.match( "hello, 1234" , regex)
if m then ngx.say(m[0]) else ngx.say( "not matched!" ) end
}
}
# evaluates to "1234"
ملحوظة: يُنصح باستخدام by_lua_file
عندما يكون رمز Lua طويلًا جدًا.
العودة إلى جدول المحتويات
إن خلط SSI مع ngx_lua في نفس طلب Nginx غير مدعوم على الإطلاق. ما عليك سوى استخدام ngx_lua حصريًا. كل ما يمكنك فعله باستخدام SSI يمكن القيام به فوق ngx_lua على أي حال ويمكن أن يكون أكثر كفاءة عند استخدام ngx_lua.
العودة إلى جدول المحتويات
بعض واجهات برمجة تطبيقات Lua المقدمة من ngx_lua لا تعمل في وضع SPDY الخاص بـ Nginx حتى الآن: ngx.location.capture وngx.location.capture_multi وngx.req.socket.
العودة إلى جدول المحتويات
قد يقوم Nginx بإنهاء الطلب مبكرًا باستخدام (على الأقل):
وهذا يعني أنه يتم تخطي المراحل التي يتم تشغيلها عادةً، مثل مرحلة إعادة الكتابة أو مرحلة الوصول. ويعني هذا أيضًا أن المراحل اللاحقة التي يتم تشغيلها بغض النظر، على سبيل المثال، log_by_lua، لن تتمكن من الوصول إلى المعلومات التي يتم تعيينها عادةً في تلك المراحل.
العودة إلى جدول المحتويات
bsdrecv
.ngx_hash_t
لتحسين عملية البحث عن الرأس المضمن لـ ngx.req.set_header وما إلى ذلك.ignore_resp_headers
و ignore_resp_body
و ignore_resp
إلى أساليب ngx.location.capture وngx.location.capture_multi، للسماح بضبط الأداء الجزئي من جانب المستخدم.stat
مشابهًا لـ mod_lua.العودة إلى جدول المحتويات
يتم إدراج التغييرات التي تم إجراؤها في كل إصدار من هذه الوحدة في سجلات التغيير الخاصة بحزمة OpenResty:
https://openresty.org/#Changes
العودة إلى جدول المحتويات
التبعيات التالية مطلوبة لتشغيل مجموعة الاختبار:
إصدار إنجينكس >= 1.4.2
وحدات بيرل:
وحدات إنجينكس:
يعد الترتيب الذي تتم به إضافة هذه الوحدات أثناء التكوين مهمًا لأن موضع أي وحدة مرشح في سلسلة التصفية يحدد الإخراج النهائي، على سبيل المثال. يظهر ترتيب الإضافة الصحيح أعلاه.
مكتبات Lua التابعة لجهات خارجية:
التطبيقات: