Skip to content
العودة إلى المدوّنة
دروس تعليمية

أولوية location في Nginx: شرح ترتيب المطابقة

كيف يختار nginx كتلة location فعليًا: الترتيب الدقيق لـ = و^~ و~ والبادئات، إضافة إلى الأخطاء التي تُعطّل الإعدادات، مع أداة اختبار مجانية عبر الإنترنت.

12 دقائق للقراءة

أولوية location في Nginx: شرح ترتيب المطابقة

لا يقرأ nginx كتل location من الأعلى إلى الأسفل ليتوقف عند أول كتلة تناسب الطلب. هذا الالتباس وحده يقف خلف معظم البلاغات من نوع «كتلة location عندي لا تعمل». فمع كتل البادئة، لا أثر إطلاقًا لموضع الكتلة داخل الملف، إذ يقارن nginx الكتل كلها ويحتفظ بأطول تطابق.

أولوية location الحقيقية في nginx هي تسلسل ثابت من أربع خطوات:

  1. المطابقة التامة. إذا ساوت location = /path الـ URI، استخدمها nginx وتوقّف. بلا مقارنة بادئات، وبلا تعبيرات نمطية.
  2. أطول بادئة. تُقارَن كل كتلة بادئة (location /path وlocation ^~ /path) يبدأ بها الـ URI. والأطول تُحفَظ فحسب، ولا تُستعمَل في هذه المرحلة.
  3. الاختصار عبر ^~. إذا حملت البادئة المحفوظة ^~، تخطّى nginx مرحلة التعبيرات النمطية بالكامل واستخدم تلك الكتلة.
  4. التعبيرات النمطية، بترتيب الملف. وإلا فتُجرَّب كتل ~ و~* بالترتيب الذي تظهر به في الإعداد، ويفوز أول تطابق. فإن لم يطابق أيٌّ منها، استُخدمت البادئة المحفوظة في الخطوة 2.

قاعدتان من هذه القواعد تشدّان في اتجاهين متعاكسين: البادئات تُنتقى بالطول بصرف النظر عن الترتيب، والتعبيرات النمطية بالترتيب بصرف النظر عن الطول. وقراءة الإعداد من أعلى إلى أسفل لن تكشف هذا التعارض أبدًا. وإن أردت الجواب لملفك أنت لا للأمثلة أدناه، فالصقه في مختبر nginx location المجاني. فهو يعيد تشغيل هذا التسلسل ويُظهر المرحلة التي سقطت عندها كل كتلة خاسرة. وهو يعمل داخل متصفحك، فإعداد الإنتاج الذي تلصقه لا يغادر الصفحة أبدًا. وكل قاعدة مطابقة وردت هنا جرى التحقق منها على nginx 1.27.5 قيد التشغيل، لا نقلًا عن مقالات ثانوية.

أولوية location في Nginx بلمحة

خمسة مُعدِّلات تشارك في مطابقة الـ URI، وسادس لا يشارك.

المُعدِّلالصيغةيطابق بحسبيوقف مرحلة التعبيرات النمطيةالاستخدام المعتاد
=location = /pathالتساوينعمالمسارات كثيفة الطلب مثل / أو /favicon.ico
^~location ^~ /pathالبدء بـنعم، إن كانت أطول بادئةالمجلدات التي يجب ألّا تصل إلى تعبير نمطي أبدًا
~location ~ regexPCRE، حساس لحالة الأحرفلاالتوجيه حسب الامتداد حين تهمّ الحالة
~*location ~* regexPCRE، غير حساس لحالة الأحرفلاالتوجيه حسب الامتداد حين لا تهمّ الحالة
(بلا مُعدِّل)location /pathالبدء بـلاالتوجيه العام حسب المسار
@location @nameلا يُطابَق بالـ URI أبدًاأهداف error_page وtry_files

القاعدة التقريبية: المطابقة التامة تغلب كل شيء، والتعبير النمطي يغلب البادئة، والبادئات يغلب بعضها بعضًا بالطول. والاستثناء الوحيد هو ^~، وهو أضيق مما يبدو.

لكن الجدول لا يرتّب المُعدِّلات ترتيبًا صارمًا. فـ ^~ يعلو فيه على ~، ومع ذلك تخسر كتلة ^~ أمام تعبير نمطي بانتظام، لأن المُعدِّل لا يُستشار إلا على البادئة التي فازت أصلًا بالطول.

خوارزمية الاختيار ذات الخطوات الأربع

أسهل طريقة لتعلّم ترتيب مطابقة location في nginx هي إعداد واحد يُفعِّل القواعد كلها دفعة واحدة. هذا هو المثال الوارد في توثيق nginx، ويستحق أن يُحفَظ:

server {
    location = /                   { return 200 "A\n"; }
    location /                     { return 200 "B\n"; }
    location /documents/           { return 200 "C\n"; }
    location ^~ /images/           { return 200 "D\n"; }
    location ~* \.(gif|jpg|jpeg)$  { return 200 "E\n"; }
}

خمسة طلبات، وخمس إجابات مختلفة:

الطلبالفائزالسبب
/Aمطابقة تامة. ينتهي البحث فورًا.
/index.htmlBلم يطابق أي تعبير نمطي، فاستُخدمت البادئة المحفوظة.
/documents/document.htmlCبادئة أطول من /.
/images/1.gifDفاز ^~ في مرحلة البادئات، فلم تُشغَّل التعبيرات النمطية أصلًا.
/documents/1.jpgEتغلّب التعبير النمطي على بادئة أطول لا تحمل ^~.

قارن الصفّين الأخيرين. /images/ و/documents/ كلاهما بادئة، وكلاهما يطابق، وكلاهما أطول تطابق لطلبه. ومع ذلك يذهب أحد الطلبين إلى كتلة البادئة والآخر إلى التعبير النمطي. والفرق الوحيد محرفان.

الخطوة 2 هي التي تفوت معظم الناس: nginx لا يستخدم أطول بادئة، بل يتذكّرها. فالكتلة مرشّحة لا أكثر، ومرحلة التعبيرات النمطية ما زال بوسعها انتزاع الطلب منها. الخطوات 1 و3 و4 وحدها هي التي تُنهي البحث.

لماذا تُقاس «أطول بادئة» بالمحارف لا بمقاطع المسار

مقارنة البادئات مقارنة نصية صرفة. لا تعرف أن / يفصل مقاطع المسار، ولا تتوقف عند حدٍّ فاصل. خذ هذا الإعداد:

server {
    location /static  { }
    location /static/ { }
}

طلبٌ لـ /staticfoo تخدمه location /static. فالـ URI يبدأ بتلك المحارف السبعة، فهو مطابق. أما /static/ فلا تطابق إطلاقًا، إذ لا شرطة مائلة في ذلك الموضع. وطلبٌ لـ /static/x يسلك الاتجاه الآخر ويأخذ /static/، وهي الأطول بين الاثنتين.

والنتيجة أن location /static تملك أيضًا /static-backup و/staticfiles وكل ما تصادف أن يبدأ بالحروف نفسها. فإن كنت تقصد مجلدًا، فاكتب الشرطة المائلة الختامية وأضف كتلة مطابقة تامة للمسار المجرّد:

server {
    location /static/ { root /var/www; }
    location = /static { return 301 /static/; }
}

معظم الشروحات تستعمل أمثلة مسارات مرتّبة لا تكشف هذا أبدًا، ولذلك يفلت هذا العيب من مراجعة الشفرة مرارًا. أما مختبر nginx location فيعرض كل كتلة طابقت وعدد المحارف التي طابقت عليها، فتصبح البادئة التي تبتلع جاراتها ظاهرة للعيان بدل أن تُستنتَج.

ما الذي يعنيه ^~ فعلًا (وما لا يعنيه)

الوصف الشائع لمُعدِّل ^~ في nginx هو أنه «يجعل هذه الكتلة تسبق التعبيرات النمطية». وهو قريب من الصواب بما يكفي ليكون خطِرًا.

ما يفعله ^~ حقًا: لا شيء البتة أثناء مقارنة البادئات. لا يُطيل التطابق، ولا يرفع الكتلة فوق بادئات أخرى، ولا يغيّر أي بادئة تُحفَظ. إنما يُفحَص بعد ذلك، على البادئة الوحيدة التي فازت أصلًا بالطول. فإن حملت الفائزة ^~، تُتخطّى مرحلة التعبيرات النمطية. وإن لم تحملها، جرت المرحلة كالمعتاد.

ومعنى ذلك أن بادئة عادية أطول تعطّله في صمت:

server {
    location ^~ /a/    { }
    location /a/b/     { }
    location ~ \.php$  { }
}

طلبٌ لـ /a/b/x.php يعالجه ~ \.php$. فـ /a/b/ هي أطول بادئة مطابقة، وهي ما يحفظه nginx؛ ومُعدِّلها العادي يسمح بمرحلة التعبيرات النمطية؛ فيطابق التعبير النمطي أولًا ويأخذ الطلب. وتبقى كتلة ^~ في الملف، ما زالت تبدو واقية، ولا شأن لها بهذا الطلب على الإطلاق.

بدّل الـ URI إلى /a/x.php وسيسلك الإعداد نفسه سلوكًا مختلفًا تمامًا: صارت ^~ /a/ هي أطول تطابق، فتُتخطّى مرحلة التعبيرات النمطية وتفوز كتلة ^~. الملف نفسه، وشكل الطلب نفسه، ونتيجة معاكسة.

وللفارق أثر عملي مباشر. فالاستعمال الكلاسيكي لـ ^~ هو إبعاد مجلد قابل للكتابة عن مفسِّر الشفرة:

server {
    location ^~ /uploads/ { }
    location ~ \.php$     { fastcgi_pass unix:/run/php-fpm.sock; }
}

احذف ^~ وسيذهب طلبٌ لـ /uploads/evil.php مباشرة إلى PHP-FPM. هذا هو الشكل الكامن خلف سلسلة طويلة من بلاغات «الرفع يؤدي إلى RCE»، والفرق بين الهشّ والآمن محرفان. ولهذا أيضًا تهمّ حالة «^~ المهزوم»: إضافة بادئة عادية أطول مثل location /uploads/thumbs/ تعيد فتح الثغرة لكل ما تحتها، والتعديل الذي يفعل ذلك يبدو بريئًا تمامًا.

انتبه للنطاق كذلك. ^~ لا يكبح إلا التعبيرات النمطية المعلَنة في مستواه هو؛ ولا يكبح أبدًا تعبيرات نمطية متداخلة داخل كتلته، كما أن ^~ على كتلة متداخلة لا يحمي من تعبير نمطي معلَن على مستوى server. بدّل المُعدِّل في مختبر nginx location وراقب تغيّر الفائز؛ فهو يسمّي كل تعبير نمطي تخطّاه بدل أن يدعه يختفي من الجدول.

كتل التعبيرات النمطية: الترتيب يغلب الدقة

يستعمل التعبير النمطي في location عند nginx المُعدِّل ~ للمطابقة الحساسة لحالة الأحرف و~* لغير الحساسة. أما مطابقة البادئات فحساسة لحالة الأحرف دائمًا على Linux. (وعلى أنظمة الملفات غير الحساسة للحالة مثل macOS، يقارن nginx البادئات بلا حساسية للحالة ويجبر كل كتلة تعبير نمطي على التصرف كأنها ~*. فإن كنت تطوّر على Mac وتنشر على Linux، فقد يخفي هذا الفارق قاعدة معطوبة حتى لحظة الإطلاق.)

والقاعدة التي توقع الناس هي هذه: تُقيَّم التعبيرات النمطية بالترتيب الذي تظهر به في ملف الإعداد، وأول تطابق يُنهي البحث. أما الدقة والطول والتثبيت فلا أثر لها في الترتيب.

server {
    location ~ ^/a       { }
    location ~ ^/a/b/c$  { }
}

طلبٌ لـ /a/b/c يأخذه ~ ^/a. أما الكتلة الثانية فتطابق الـ URI بالضبط، وهي أدقّ بكثير، ولن تُنفَّذ لأي طلب كان. إنها إعداد ميت يقبله nginx -t دون كلمة واحدة.

فالعادة الصحيحة: رتّب التعبيرات النمطية من الأدقّ إلى الأعمّ، وأبقِ القائمة قصيرة. فنمط فضفاض قرب القمة يجعل كل ما تحته غير قابل للوصول، ولأن تعديلًا يعيد ترتيب الأسطر فقط يبدو غير ضار، فإن العطل يظهر عادةً أثناء عملية تنظيف لا أثناء تطوير ميزة.

والتثبيت يستحق العناية ذاتها. location ~ /admin غير مثبّت من أي طرف، فيبحث في أي موضع من الـ URI ويطابق /public/admin/x بلا تردد. اكتب ~ ^/admin حين تقصد البداية. أما التثبيت من الطرف الأخير وحده، كما في ~ \.php$، فطبيعي وصحيح للتوجيه حسب الامتداد.

وهذه تفاصيل في PCRE تخطئ فيها البديهة القادمة من JavaScript:

  • يصرّف nginx أنماط location بمحرّك PCRE، بلا وضع UTF ولا وضع الأسطر المتعددة، فتعمل الأنماط على البايتات ويثبّت ^ عند بداية الـ URI فقط.
  • في PCRE يطابق $ كذلك ما قبل سطر جديد ختامي مباشرةً. فـ URI ينتهي بـ %0A ما زال يحقق \.php$، وهي طريقة معروفة للتسلل من قواعد مبنية على امتداد الملف.
  • تكثر في PCRE تراكيب لا مقابل لها في JavaScript: المجموعات الذرّية (?>…)، والمكمِّمات التملّكية a*+، والمُعدِّلات المضمّنة مثل (?i)، وأصناف POSIX مثل [[:alpha:]]، وهروب مثل \A و\z و\K و\Q…\E.
  • أي نمط يحتوي { أو } يجب وضعه بين علامتَي اقتباس. فـ location ~ ^/a{2}$ يفشل في التحميل مع الرسالة unknown directive "2}$"، لأن القوس ينهي الوحدة عند محلّل الإعداد. اكتب location ~ "^/a{2}$".

أما مجموعات الالتقاط فتعمل كما تتمنى، و$1 وما بعدها متاحة داخل الكتلة:

upstream backend {
    server 127.0.0.1:8080;
}

server {
    location ~ ^/user/(\d+)/profile$ {
        proxy_pass http://backend/profiles/$1;
    }
}

وإن كنت ما زلت تصحّح النمط نفسه لا موضعه في الملف، فاختبره أولًا في أداة اختبار regex؛ ويغطي مرجع التعبيرات النمطية هذه الصيغة بتفصيل أوسع.

الخطوة التي يتخطاها الجميع: تسوية الـ URI

قبل استشارة أي كتلة location، يعيد nginx كتابة هدف الطلب. فأنماطك تُقارَن بالمسار بعد التسوية، لا بالبايتات التي وصلت عبر الشبكة. لا يكاد أي شرح يذكر هذا، وهو يحسم عددًا مفاجئًا من حالات «كتلة location عندي لا تطابق».

تفعل التسوية أربعة أشياء: تفصل سلسلة الاستعلام، وتفكّ ترميز النسبة المئوية في المسار، وتحلّ مقطعَي . و..، وتدمج الشرطات المائلة المكررة.

هدف الطلب$uri بعد التسويةملاحظة
//a//x/a/xدُمجت الشرطات المائلة المكررة
/a/../b/x/b/xحُلّت .. قبل المطابقة
/a/b%2F..%2Fzz/a/zz%2F يُفكّ إلى فاصل حقيقي فينضم إلى عملية الحل
/a/%2e%2e/b/x/b/x%2E يُفكّ إلى نقطة تشارك هي الأخرى
/a%20b/x/a b/x%20 يصير مسافة حقيقية
/a+b/x/a+b/x+ ليس مسافة داخل المسار
/a?x=/b/aتُفصَل سلسلة الاستعلام أولًا
/a%3Fx=1/a?x=1%3F يبقى حرفيًا؛ وسلسلة الاستعلام فارغة

ثلاثة محارف مفكوكة تشكّل استثناءً وتُكتب كما هي دون إعادة تفسير: %25 و%23 و%3F. ولهذا ينتهي /a%3Fx=1 بعلامة استفهام داخل المسار ولا شيء في $args.

وهناك هدفان لا يبلغان اختيار location أصلًا. فمقاطع .. التي تصعد فوق الجذر، والهروب غير الصالح مثل %00، كلاهما يُرفَض بالرمز 400 قبل أن تبدأ المطابقة.

ولهذا أثر أمني مباشر. فإن كنت تستعمل كتلة location حدًّا للتحكم بالوصول، فالمسار الذي كتبته يُقارَن بالمسار بعد الحل:

server {
    location /a/ { }
    location /b/ { }
}

طلبٌ لـ /a/b%2F..%2Fzz لا يبقى تحت /a/b/. إنه يُسوّى إلى /a/zz وتعالجه location /a/. والتفكير في الهدف الخام بدل $uri يعطي الجواب الخطأ هنا، و«الجواب الخطأ» في سياق التحكم بالوصول له اسم محدد. فقبل أن تعتمد على location /admin لحماية أي شيء، تأكّد من المسار المُسوّى فعلًا. يعرض مختبر nginx location الهدف الخام و$uri بعد التسوية وسلسلة الاستعلام المفصولة في ثلاثة صفوف منفصلة. وإن كنت تحتاج فقط إلى التفكير في الترميز نفسه، فإن ترميز وفك ترميز URL يتكفّل بذلك على حدة.

ونتيجة أخرى لا بد من قولها صراحة: سلسلة الاستعلام لا تشارك في المطابقة إطلاقًا. فـ location /search?q= لا يمكن أن تطابق طلبًا لـ /search?q=1، لأن الاختيار لا يرى سوى /search. وللتفريع حسب معامل، اقرأ $arg_name داخل الكتلة.

خمسة إعدادات لا تفعل ما تظنه

كتلة ^~ تخسر أمام بادئة عادية أطول

العَرَض: مجلد يحمل ^~ يبدو محميًا، ومع ذلك يعالج تعبير نمطي الطلبات داخله. السبب: ^~ لا يُستشار إلا على البادئة التي فازت أصلًا بالطول. فتُحفَظ بدلًا منها بادئة عادية أطول، وهي لا تكبح شيئًا. الحل: ضع ^~ على البادئة الأطول أيضًا، أو احذف البادئة الأطول.

# Broken: /a/b/x.php goes to the regex
location ^~ /a/    { }
location /a/b/     { }
location ~ \.php$  { }

# Fixed: /a/b/x.php goes to ^~ /a/b/
location ^~ /a/    { }
location ^~ /a/b/  { }
location ~ \.php$  { }

بادئة بلا شرطة مائلة ختامية تبتلع جاراتها

العَرَض: كتلة مقصودة لمجلد واحد تخدم أيضًا مسارات لا يجمعها بها سوى بدايتها الحرفية. السبب: مطابقة البادئات تقارن المحارف لا مقاطع المسار، فـ location /app تطابق /application كذلك. الحل: اكتب الشرطة المائلة الختامية، وأضف location = /app إن كان المسار المجرّد يحتاج معالجة أيضًا.

تعبير نمطي دقيق تحت نمط عام

العَرَض: قاعدة دقيقة لا تُطلَق أبدًا، ولا يظهر أي خطأ في أي مكان. السبب: تُجرَّب التعبيرات النمطية بترتيب الملف وأول تطابق يُنهي البحث، فكل ما تحت نمط فضفاض غير قابل للوصول. الحل: انقل النمط الدقيق فوق الفضفاض، أو ضيّق الفضفاض بمثبِّت.

تعبير نمطي مكتوب بعد ^~

العَرَض: قاعدة deny تُحمَّل بلا مشاكل ولا تحجب شيئًا. السبب: ^~ يأخذ بادئة حرفية لا نمطًا. ولا يشتكي nginx أبدًا؛ الكتلة ببساطة لا تطابق أي URI. الحل: استعمل مُعدِّل التعبير النمطي.

# Broken: matches nothing, loads without error
location ^~ "\.php$" { deny all; }

# Fixed
location ~ \.php$ { deny all; }

افتراض أن سلسلة الاستعلام تشارك في المطابقة

العَرَض: كتلة location تحتوي ? لا تطابق أبدًا. السبب: تُفصَل سلسلة الاستعلام أثناء التسوية، ويجري اختيار location على المسار وحده. الحل: طابِق على المسار وافحص $arg_name داخل الكتلة.

location /search {
    if ($arg_q = "") { return 400; }
}

تصحيح الأخطاء: اعرف أي كتلة فازت فعلًا

سجل التنقيح هو الجواب الموثوق، وهو أيضًا الأكثر كلفة في الإعداد. يحتاج إلى ملف تنفيذي مبني بدعم التنقيح، فتحقّق أولًا:

nginx -V 2>&1 | grep -o with-debug

ثم فعّله وابحث عن السطر الذي يسمّي الكتلة المختارة:

error_log /var/log/nginx/debug.log debug;
grep "using configuration" /var/log/nginx/debug.log

سبر ترويسات الاستجابة أسرع ولا يحتاج بنية تنقيح. ضع وسمًا على كل مرشّح واقرأ الترويسات:

location ^~ /uploads/ {
    add_header X-Debug-Location "uploads-caret" always;
    return 204;
}
location ~ \.php$ {
    add_header X-Debug-Location "php-regex" always;
    return 204;
}
curl -sI --path-as-is 'http://localhost/uploads/evil.php' | grep -i x-debug-location

--path-as-is مهم: من دونه يتفضّل curl بحلّ .. نيابةً عنك فتنتهي إلى اختبار URI غير الذي قصدته. وإن كنت تركّب أمرًا أعقد، فإن منشئ أوامر cURL يكتب الرايات عنك، وتغطي ورقة غش curl بقية الأمر. وحين يعود السبر بإعادة توجيه أو 404 بدل ترويستك، فمرجع أكواد حالة HTTP سيخبرك عادةً أي وحدة أنتجته.

nginx -T يطبع الإعداد المدمج بالكامل، بملفات include كلها. وهكذا تكتشف الترتيب الحقيقي لتعبيراتك النمطية بعد تجميع ستة ملفات، وهو نادرًا ما يطابق ترتيبها في الملف الذي كنت تحرّره.

nginx -T | grep -n "location"

أعِد إنتاج العطل في مختبر nginx location قبل أن تحرّر الخادم. فالتكرار على إعداد لم تنشره أسرع من دورة إعادة تحميل، وجدول القرار يسمّي المرحلة التي أُقصيت عندها كل كتلة بدل أن يترك لك استنتاجها.

الكتل المتداخلة وtry_files وما لا تغيّره

تُشغّل الكتل المتداخلة الخوارزمية نفسها بمستوى أدنى. فما إن تفوز كتلة بادئة، ينزل nginx إلى أبنائها ويعيد البحث هناك، ما يعني أن تعبيرًا نمطيًا متداخلًا يُجرَّب قبل التعبيرات النمطية في المستوى الأب:

server {
    location ~ \.php$ { }
    location /a/ {
        location ~ \.php$ { return 200 "nested\n"; }
    }
}

/a/x.php تعالجه الكتلة المتداخلة. وللتداخل أثر آخر أقل وضوحًا: قد يجعل بادئة أطول على المستوى العام غير قابلة للوصول، لأن النزول لا يحدث إلا داخل الفائز في كل مستوى. فإن كانت location /a/bb/ متداخلة داخل location /a/، وكانت location /a/b شقيقة لها في المستوى الخارجي، فإن طلبًا لـ /a/bb/x يذهب إلى /a/b. فالمقارنة الخارجية تحدث أولًا، و/a/b تفوز بها. وإذا نزل البحث ولم يجد شيئًا فلا يعود أدراجه، بل يحتفظ الأب بالطلب.

وtry_files وrewrite ليستا جزءًا من الاختيار. إنهما تُنفَّذان داخل الكتلة التي فازت أصلًا، ولا تستطيعان الرجوع لتغيير ذلك. فإن كان الطلب لا يصل أبدًا إلى الكتلة التي تحوي try_files، فالتوجيه بلا معنى، والمتّهم المعتاد هو تعبير نمطي ~ \.php$ يخطف الطلب قبل أن يأتي دور كتلة البادئة. ويبقى استثناء واحد: إعادة التوجيه الداخلية (rewrite … last، أو قفزة error_page) تعيد تشغيل المطابقة، فيُحَلّ الـ URI المعاد كتابته على قائمة location من جديد ومن أولها.

والرمز 301 الذي تحصل عليه عند طلب مجلد بلا شرطة مائلة ختامية ليس فشلًا في المطابقة. آليتان منفصلتان تنتجانه. فإذا حملت كتلة location ينتهي اسمها بـ / توجيه proxy_pass أو أي توجيه *_pass آخر، فإن طلبًا للمسار نفسه بلا الشرطة يُجاب بالرمز 301 أثناء الاختيار، قبل تقييم أي تعبير نمطي، ومع الحفاظ على سلسلة الاستعلام:

server {
    location /user/ { proxy_pass http://backend/; }
}
# GET /user?x=1  ->  301 to /user/?x=1

وإضافة location = /user تكبح إعادة التوجيه تلك. وبمعزل عن ذلك، تُصدر وحدة الملفات الساكنة رمز 301 خاصًا بها حين يُحَلّ المسار إلى مجلد حقيقي على القرص، وهذا يتوقف على نظام ملفاتك لا على إعدادك.

الأسئلة الشائعة

ما هي مُعدِّلات location الخمسة في nginx؟

مُعدِّلات location الخمسة في nginx هي = للمطابقة التامة، و^~ لبادئة تتخطى مرحلة التعبيرات النمطية، وغياب المُعدِّل لبادئة عادية، و~ لتعبير نمطي حساس لحالة الأحرف، و~* لتعبير غير حساس لها. وهناك صيغة سادسة، location @name، لا تشارك في مطابقة الـ URI إطلاقًا ولا وجود لها إلا كهدف لـ error_page وtry_files.

هل تجعل المطابقة التامة = عمل nginx أسرع؟

كتلة المطابقة التامة تُنهي البحث فورًا، فتتخطى مسح البادئات وكل تقييم لتعبير نمطي. والتوفير حقيقي لكنه أصغر من أن يُلاحَظ. وهو يستحق الكتابة لنقاط النهاية التي تُطلَب آلاف المرات في الثانية، مثل فحوص الصحة أو /favicon.ico. أما كومة من كتل = لصفحات عادية فتكلّف من تعقيد الإعداد أكثر مما تعطي.

هل يمكنني كتابة مُعدِّل location بلا مسافة، مثل ~*^/api؟

نعم. location ~*^/api/ وlocation ~* ^/api/ تعنيان الشيء نفسه تمامًا، لأن nginx ينزع المُعدِّل من مقدمة الاسم ويطابق أطول مُعدِّل أولًا، فيُتعرَّف على ~* قبل ~. أبقِ المسافة رغم ذلك. فالمُعدِّل الملتصق يبدو جزءًا من النمط، ويقرأه المراجع البشري خطأ.

ما الفرق بين root وalias داخل كتلة location؟

root يُلحق الـ URI كاملًا بالمجلد، بينما alias يستبدل به البادئة المطابِقة. فمع location /static/ { root /var/www; } يبحث طلبٌ لـ /static/x.css عن /var/www/static/x.css؛ وبالتحويل إلى alias /var/www/assets/; يبحث عن /var/www/assets/x.css. ومع alias، إما أن تعطي كلًّا من كتلة location والمسار شرطة مائلة ختامية، وإما ألّا تعطيها لأيٍّ منهما.

هل يمكن أن يطابق طلب واحد أكثر من كتلة location؟

قد تطابق عدة كتل، لكن كتلة واحدة بالضبط هي التي تعالج الطلب. يقارن nginx كل كتلة بادئة، وعند الحاجة كل كتلة تعبير نمطي، ثم يسلّم الطلب إلى الفائز الوحيد. ولا تُورَّث التوجيهات من الكتل الخاسرة؛ فأي شيء تحتاجه في كل مكان يجب أن يوضع على مستوى server أو http، أو أن يُكرَّر.

هل يخبرني nginx -t أي كتلة location ستطابق؟

لا. nginx -t يفحص الصيغة وصحة الإعداد؛ وهو لا يحاكي طلبًا أبدًا، فلا يقول شيئًا عن ترتيب المطابقة. ولمعرفة الكتلة التي تملك URI معينًا، اقرأ سجل التنقيح، أو أضف ترويسة استجابة مؤقتة، أو الصق الإعداد في مختبر nginx location واقرأ سبب فوز كل كتلة أو خسارتها.

الوسوم: nginx web-server devops regex configuration

مقالات ذات صلة

عرض جميع المقالات