---
title: "مقدمة عن واجهات برمجة التطبيقات (APIs) الشائعة في OpenResty - API7.ai"
description: "ستقدم لك هذه المقالة استخدام واجهات برمجة التطبيقات الشائعة في OpenResty للتعامل مع الوقت، التعبيرات النمطية (Regular Expressions)، وغيرها من القضايا الشائعة."
url: "https://api7.ai/ar/learning-center/openresty/introduction-openresty-common-apis"
---

# مقدمة عن واجهات برمجة التطبيقات (APIs) الشائعة في OpenResty

API7.ai

November 4, 2022

[OpenResty (NGINX + Lua)](https://api7.ai/learning-center/openresty)

في المقالات السابقة، تعرفت على العديد من واجهات برمجة التطبيقات (APIs) المهمة في Lua في OpenResty. اليوم، سنتعلم عن بعض واجهات برمجة التطبيقات العامة الأخرى، والتي ترتبط بشكل رئيسي بالتعبيرات العادية، الوقت، العمليات، وما إلى ذلك.

## واجهات برمجة التطبيقات المتعلقة بالتعبيرات العادية

لنبدأ بالنظر إلى التعبيرات العادية الأكثر استخدامًا والأهم. في OpenResty، يجب علينا استخدام مجموعة واجهات برمجة التطبيقات التي توفرها `ngx.re.*` للتعامل مع المنطق المتعلق بالتعبيرات العادية بدلاً من استخدام مطابقة الأنماط في Lua. هذا ليس فقط لأسباب تتعلق بالأداء ولكن أيضًا لأن التعبيرات العادية في Lua مكتفية ذاتيًا وليست مواصفة `PCRE`، مما قد يكون مزعجًا لمعظم المطورين.

في المقالات السابقة، صادفت بالفعل بعض واجهات برمجة التطبيقات `ngx.re.*`، والتي تكون وثائقها مفصلة جدًا. لذلك لن أذكرها مرة أخرى. هنا، سأقدم واجهتي برمجة التطبيقات التاليتين بشكل منفصل.

### `ngx.re.split`

الأولى هي `ngx.re.split`. تقسيم السلاسل النصية هو وظيفة شائعة جدًا، وOpenResty يوفر أيضًا واجهة برمجة تطبيقات مقابلة، ولكن العديد من المطورين لا يمكنهم العثور على مثل هذه الوظيفة ويضطرون إلى اختيار تنفيذها بأنفسهم.

لماذا؟ لأن واجهة برمجة التطبيقات `ngx.re.split` ليست في `lua-nginx-module` ولكن في `lua-resty-core`؛ وهي ليست في وثائق الصفحة الرئيسية لـ `lua-resty-core` ولكن في وثائق الدليل الثالث `lua-resty-core/lib/ngx/re.md`. نتيجة لذلك، العديد من المطورين غير مدركين تمامًا لوجود هذه الواجهة.

وبالمثل، تشمل واجهات برمجة التطبيقات التي يصعب اكتشافها `ngx_resp.add_header`، `enable_privileged_agent`، وغيرها، والتي ذكرناها سابقًا. إذن كيف يمكننا حل هذه المشكلة بسرعة؟ بالإضافة إلى قراءة وثائق الصفحة الرئيسية لـ `lua-resty-core`، تحتاج إلى قراءة وثائق `*.md` في دليل `lua-resty-core/lib/ngx/` أيضًا.

### `lua_regex_match_limit`

ثانيًا، أريد أن أقدم `lua_regex_match_limit`. لم نتحدث من قبل عن أوامر NGINX التي يوفرها OpenResty لأنه في معظم الحالات تكون القيم الافتراضية كافية، ولا داعي لتعديلها أثناء التشغيل. الاستثناء من ذلك هو الأمر `lua_regex_match_limit`، الذي يتعلق بالتعبيرات العادية.

نحن نعلم أنه إذا استخدمنا محرك تعبيرات عادية يعتمد على NFA مع التراجع، فهناك خطر من التراجع الكارثي (Catastrophic Backtracking)، حيث يتراجع التعبير العادي كثيرًا عند المطابقة، مما يتسبب في أن يصبح CPU بنسبة 100% ويتم حظر الخدمات.

بمجرد حدوث تراجع كارثي، نحتاج إلى استخدام `gdb` لتحليل الـ dump أو استخدام `systemtap` لتحليل البيئة المباشرة لتحديده. لسوء الحظ، اكتشافه مسبقًا ليس سهلًا لأن فقط الطلبات الخاصة ستؤدي إلى تشغيله. هذا يسمح للمهاجمين بالاستفادة من ذلك، و`ReDoS` (RegEx Denial of Service) يشير إلى هذا النوع من الهجمات.

هنا، أقدم لكم بشكل رئيسي كيفية استخدام السطر التالي من الكود في OpenResty لتجنب المشاكل المذكورة أعلاه ببساطة وفعالية:

`lua_regex_match_limit` يستخدم للحد من عدد التراجعات بواسطة محرك التعبيرات العادية `PCRE`. بهذه الطريقة، حتى إذا حدث تراجع كارثي، ستكون العواقب محدودة ضمن نطاق لن يتسبب في امتلاء CPU الخاص بك.

```
lua_regex_match_limit 100000;
```

## واجهات برمجة التطبيقات المتعلقة بالوقت

أكثر واجهات برمجة التطبيقات المتعلقة بالوقت استخدامًا هي `ngx.now`، والتي تطبع الطابع الزمني الحالي، مثل السطر التالي من الكود:

```
resty -e 'ngx.say(ngx.now())'
```

كما ترى من النتائج المطبوعة، `ngx.now` تتضمن الجزء الكسري، لذا فهي أكثر دقة. واجهة برمجة التطبيقات ذات الصلة `ngx.time` تعيد فقط الجزء الصحيح من القيمة. الباقي، `ngx.localtime`، `ngx.utctime`، `ngx.cookie_time` و `ngx.http_time` تستخدم بشكل رئيسي لإعادة ومعالجة الوقت بتنسيقات مختلفة. إذا كنت تريد استخدامها، يمكنك التحقق من الوثائق، فهي ليست صعبة الفهم، لذا لا داعي للحديث عنها.

ومع ذلك، تجدر الإشارة إلى أن **هذه الواجهات التي تعيد الوقت الحالي، إذا لم يتم تشغيلها بواسطة عملية IO شبكية غير متوقفة، ستظل تعيد القيمة المخزنة مؤقتًا بدلاً من الوقت الحقيقي الحالي كما نريد**. انظر إلى نموذج الكود التالي:

```
$ resty -e 'ngx.say(ngx.now())
os.execute("sleep 1")
ngx.say(ngx.now())'
```

بين الاستدعائين لـ `ngx.now`، استخدمنا وظيفة Lua المتوقفة للنوم لمدة `1` ثانية، ولكن الطابع الزمني الذي تم إرجاعه هو نفسه في كلتا الحالتين، كما يظهر من النتائج المطبوعة.

إذن، ماذا لو استبدلناها بوظيفة نوم غير متوقفة؟ على سبيل المثال، الكود الجديد التالي:

```
$ resty -e 'ngx.say(ngx.now())
ngx.sleep(1)
ngx.say(ngx.now())'
```

سيطبع طابعًا زمنيًا مختلفًا. هذا يقودنا إلى `ngx.sleep`، وهي وظيفة نوم غير متوقفة. بالإضافة إلى النوم لفترة زمنية محددة، هذه الوظيفة لها غرض خاص آخر.

على سبيل المثال، إذا كان لديك جزء من الكود يقوم بحسابات مكثفة، والتي تستغرق الكثير من الوقت، فإن الطلبات المقابلة لهذا الجزء من الكود ستستمر في استهلاك موارد العامل وCPU خلال هذا الوقت، مما يتسبب في تراكم الطلبات الأخرى وعدم الحصول على استجابة في الوقت المناسب. في هذه الحالة، يمكننا إدراج `ngx.sleep(0)` لجعل هذا الكود يتخلى عن التحكم حتى يمكن معالجة الطلبات الأخرى أيضًا.

## واجهات برمجة التطبيقات المتعلقة بالعامل والعمليات

يوفر OpenResty واجهات برمجة التطبيقات `ngx.worker.*` و `ngx.process.*` للحصول على معلومات عن العمال والعمليات. الأولى تتعلق بعمليات عامل Nginx، بينما تشير الثانية إلى جميع عمليات Nginx بشكل عام، ليس فقط عمليات العامل، ولكن أيضًا العملية الرئيسية، العملية المميزة، وما إلى ذلك.

## مشكلة قيم `true` و `null`

أخيرًا، لننظر إلى مشكلة قيم `true` و `null`. في OpenResty، تحديد قيمة `true` وقيم `null` كان دائمًا نقطة إشكالية ومربكة.

لننظر إلى تعريف قيمة `true` في Lua: باستثناء `nil` و `false`، كلها قيم `true`.

إذن، قيم `true` ستشمل أيضًا `0`، سلسلة نصية فارغة `string`، جدول فارغ `table`، إلخ.

لننظر إلى `nil` في Lua، والتي تعني `غير معرّف`. على سبيل المثال، إذا قمت بتعريف متغير ولكن لم تقم بتهيئته، فإن قيمته تكون `nil`.

```
$ resty -e 'local a
ngx.say(type(a))'
```

و `nil` هي أيضًا نوع بيانات في Lua. بعد فهم هاتين النقطتين، لننظر الآن إلى القضايا الأخرى المشتقة من هذين التعريفين.

### `ngx.null`

القضية الأولى هي `ngx.null`. لأن `nil` في Lua لا يمكن استخدامها كقيمة في `table`، قدم OpenResty `ngx.null` كقيمة `null` في الجدول.

```
$ resty -e  'print(ngx.null)'
null
```

```
$ resty -e 'print(type(ngx.null))'
userdata
```

كما ترى من الكودين أعلاه، `ngx.null` يتم طباعته كـ `null`، ونوعه هو `userdata`، فهل يمكن اعتباره قيمة `false`؟ بالطبع لا. القيمة المنطقية لـ `ngx.null` هي `true`.

```
$ resty -e 'if ngx.null then
ngx.say("true")
end'
```

لذا، تذكر أن فقط `nil` و `false` هما قيمتا `false`. إذا فاتتك هذه النقطة، فمن السهل الوقوع في الأخطاء، على سبيل المثال، عند استخدام `lua-resty-redis` وإجراء الحكم التالي:

```
local res, err = red:get("dog")
if not res then
    res = res + "test"
end
```

إذا كانت القيمة المرجعة `res` هي `nil`، فإن استدعاء الوظيفة قد فشل؛ إذا كانت `res` هي `ngx.null`، فإن المفتاح `dog` غير موجود في redis، ثم يتعطل الكود إذا كان المفتاح `dog` غير موجود.

### `cdata:NULL`

القضية الثانية هي `cdata:NULL`. عند استدعاء وظيفة C من خلال واجهة LuaJIT FFI، وإذا كانت الوظيفة ترجع مؤشر `NULL`، فستواجه نوعًا آخر من قيم `null`، وهي `cdata:NULL`.

```
$ resty -e 'local ffi = require "ffi"
local cdata_null = ffi.new("void*", nil)
if cdata_null then
    ngx.say("true")
end'
```

مثل `ngx.null`، `cdata:NULL` هي أيضًا `true`. ولكن الأكثر إرباكًا هو أن الكود التالي، الذي يطبع `true`، يعني أن `cdata:NULL` تعادل `nil`.

```
$ resty -e 'local ffi = require "ffi"
local cdata_null = ffi.new("void*", nil)
ngx.say(cdata_null == nil)'
```

إذن كيف يجب أن نتعامل مع `ngx.null` و `cdata:NULL`؟ ليس حلًا جيدًا أن نهتم بهذه المشاكل في طبقة التطبيق. من الأفضل القيام بطبقة ثانية من التغليف وعدم إعلام المتصل بهذه التفاصيل.

من الأفضل القيام بطبقة ثانية من التغليف وعدم إعلام المتصل بهذه التفاصيل.

### `cjson.null`

أخيرًا، لننظر إلى قيم `null` التي تظهر في `cjson`. مكتبة `cjson` تأخذ `NULL` في json، وتفك تشفيرها إلى `lightuserdata` في Lua، وتستخدم `cjson.null` لتمثيلها.

```
$ resty -e 'local cjson = require "cjson"
local data = cjson.encode(nil)
local decode_null = cjson.decode(data)
ngx.say(decode_null == cjson.null)'
```

`nil` في Lua تصبح `cjson.null` بعد التشفير وفك التشفير بواسطة JSON. كما يمكنك أن تتخيل، تم تقديمها لنفس السبب مثل `ngx.null`، لأن `nil` لا يمكن استخدامها كقيمة في `table`.

حتى الآن، هل تشعر بالارتباك بسبب العديد من أنواع قيم `null` في OpenResty؟ لا تقلق. اقرأ هذا الجزء عدة مرات وقم بترتيبه بنفسك، ثم لن تشعر بالارتباك. بالطبع، نحتاج إلى التفكير أكثر في المستقبل عما إذا كان يعمل عند كتابة شيء مثل `if not foo then`.

## الخلاصة

يقدم مقال اليوم واجهات برمجة التطبيقات الشائعة الاستخدام في Lua في OpenResty.

أخيرًا، سأترك لك سؤالًا: في مثال `ngx.now`، لماذا لا يتم تعديل قيمة `ngx.now` عندما لا تكون هناك عملية `yield`؟ مرحبًا بك في مشاركة رأيك في التعليقات، وأيضًا مرحبًا بك في مشاركة هذه المقالة حتى نتمكن من التواصل والتحسين معًا.

Share article link

Share

Related Posts

[![أسئلة وأجوبة حول OpenResty | كيفية استخدام OpenResty في الممارسة العملية](https://static.api7.ai/uploads/2023/02/12/jbv9M0zi_Hello%20World%20in%20OpenResty%20%283%29.png)](https://api7.ai/learning-center/openresty/faq-5)

## [أسئلة وأجوبة حول OpenResty | كيفية استخدام OpenResty في الممارسة العملية](https://api7.ai/learning-center/openresty/faq-5)

[![الجزء الثالث: كيفية بناء بوابة API للخدمات المصغرة باستخدام OpenResty](https://static.api7.ai/uploads/2023/02/07/3XJXY9Jy_45.png)](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

## [الجزء الثالث: كيفية بناء بوابة API للخدمات المصغرة باستخدام OpenResty](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

Table of Contents

- [واجهات برمجة التطبيقات المتعلقة بالتعبيرات العادية](#%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D9%84%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%AA%D8%B9%D8%A8%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B9%D8%A7%D8%AF%D9%8A%D8%A9)

  - [`ngx.re.split`](#ngxresplit)
  - [`lua_regex_match_limit`](#lua_regex_match_limit)

- [واجهات برمجة التطبيقات المتعلقة بالوقت](#%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D9%84%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D9%88%D9%82%D8%AA)

- [واجهات برمجة التطبيقات المتعلقة بالعامل والعمليات](#%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AA%D8%B9%D9%84%D9%82%D8%A9-%D8%A8%D8%A7%D9%84%D8%B9%D8%A7%D9%85%D9%84-%D9%88%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A%D8%A7%D8%AA)

- [مشكلة قيم `true` و `null`](#%D9%85%D8%B4%D9%83%D9%84%D8%A9-%D9%82%D9%8A%D9%85-true-%D9%88-null)

  - [`ngx.null`](#ngxnull)
  - [`cdata:NULL`](#cdatanull)
  - [`cjson.null`](#cjsonnull)

- [الخلاصة](#%D8%A7%D9%84%D8%AE%D9%84%D8%A7%D8%B5%D8%A9)
