ریدایرکت (redirect) و ریرایت (rewrite) | Nginx from scratch
۲۴ تیر ۱۴۰۴
دستورهای rewrite و redirect معمولاً برای ساخت URL های با معنی تر، یا انتقال کاربران به آدرسهای جدید استفاده میشوند.
با استفاده از دستورهای rewrite
و return
میتوان با حفظ آدرس فعلی, محتوای متفاوتی را به کاربر نمایش داد یا اینکه کاربر را به آدرس جدیدی انتقال داد.
دستور return
دستور return باعث خاتمه پردازش درخواست و برگرداندن استاتوس کد به کاربر میشود (مستندات). از این دستور در بلوک های if
, location
و server
میتوان استفاده کرد.
با استفاده از یکی از کدهای وضعیت 301، 302، 303، 307 یا 308 میتوان یک URL را بهعنوان پارامتر دوم مشخص کرد تا کاربر به آن آدرس هدایت شود (ریدایرکت انجام شود). در صورتی که از کد وضعیت دیگری استفاده شود، میتوان محتوای دلخواه را بهعنوان پارامتر دوم ارسال کرد تا در پاسخ به کاربر، بهعنوان بدنه ی پاسخ (body) در نظر گرفته شود.
در مثال بالا اگر یکی از آدرس ها localhost:8065
یا 127.0.0.1:8065
را در مرورگر باز کنید باید بلافاصله به مسیر /home
هدایت می شوید و سپس پاسخی که مشخص کردیم نمایش داده شود. همچنین اگر به مسیر /downloads
بروید با استاتوس کد 404
مواجه می شوید.
دستور rewrite
با استفاده از دستور rewrite علاوه بر ریدایرکت کردن به آدرس جدید, میتوان با حفظ آدرس فعلی درخواست را به مسیر دیگری فرستاد.
ساختار کلی این دستور به صورت زیر است (مستندات):
همونطور که میبینم این دستور به عنوان پارامتر اول یک پترن از نوع PCRE قبول میکنه , پارامتر دوم مسیری هست که میخوایم جایگزین بشه و در آخر از یک flag در صورت نیاز میتوان استفاده کرد.
استفاده از فلگ (flag) باعث میشود پردازش دستورالعملهای فعلی قطع شود و ادامه پیدا نکند. فلگ (flag) هایی که میتونیم استفاده کنیم به صورت لیست زیر هستند:
- redirect
- permanent
- last
- break
فلگ redirect
در صورت استفاده از redirect
, یک ریدایرکت با کد استاتوس 302
انجام خواهد شد. این دستور در زمانی استفاده می شود که مسیری که عنوان replacement مشخص میکنیم با http://
, https://
یا $scheme
شروع نشده باشد.
اگر مسیری که به عنوان replacement مشخص میکنیم با https://
, http://
و یا $scheme
شروع شود, نتیجه همانند استفاده از فلگ redirect
خواهد بود و نیازی به استفاده از این فلگ نیست.
در مثال بالا با استفاده از دستور rewrite_log
لاگ مربوط به دستورات rewrite
را فعال کردیم. اگر به مسیر /hello-man
بریم, به همراه استاتوس کد 302 به مسیر /hello-world
هدایت میشویم. بدین معنی که در مرورگر URL از /hello-man
به /hello-world
تغییر خواهد کرد.
همچنین در صورتی که به آدرس /hello-woman
بروید به مسیر hello-world
هدایت میشید. در اینجا در آدرس http://
وجود دارد که باعث می شود ریدایرکت به همراه استاتوس کد 302 انجام شود.
با استفاده از rewrite
میتوان ترافیک مربوط به یک مسیر را به مسیر دیگری هدایت کرد به مثال زیر دقت کنید:
در مثال بالا ترافیک مربوط به درخواست های /welcome
را روی /bye
ریدایرکت کردیم. در صورتی که کاربر به مسیر /welcome
برود آدرس در مرورگر به /bye
تغییر خواهد کرد.
فلگ permanent
این فلگ رفتاری مانند فلگ redirect
دارد با این تفاوت که استاتوس کد به 301 تغییر خواهد کرد. در صورتی که بخواهید یک ریدایرکت دائمی را معرفی کنید, بهتر است از این فلگ استفاده کنید.
تفاوت فلگ های redirect
و permenant
در استاتوس کدی هست که هنگام ریدایرکت برمیگردانند.
فلگ last
این فلگ باعث بازنویسی آدرس، توقف اجرای سایر دستورات rewrite
، و شروع تطبیق با location
جدیدی میشود که با آدرس تغییریافته مطابقت داشته باشد.
برخلاف فلگ های redirect
و permanent
, هنگامی که از فلگ last
استفاده میکنید آدرس مرورگر کاربر تغییری نمیکند بلکه بازنویسی آدرس در داخل nginx رخ میدهد. یعنی با حفظ آدرس وارد شده در مرورگر , به درخواست از آدرس دیگری پاسخ داده می شود.
با توجه به مثال بالا اگر در مرورگر خود به مسیر /hello-man
بروید, با حفظ آدرس , اطلاعات از مسیر /hello-world
برای شما لود خواهد شد.
با توجه به مثال بالا اگر به ادرس /hello-man
برویم, این آدرس با اولین rewrite تطبیق داده میشود و چون این rewrite دارای فلگ است (در اینجا last
) باقی rewrite هایی که در بلاک فعلی هستن (در اینجا server) تطبیق داده نخواهند شد و درخواست به /hello-world
بازنویسی میشود. سپس درخواست دوباره همانند یک درخواست جدید بازبینی می شود و چون آدرس به /hello-world
تغییر کرده است دوباره rewrite
دوم تطبیق داده میشود و درخواست به مسیر /bye
بازنویسی می شود و در نهایت روی صفحه Bye bye
را خواهیم دید.
فلگ break
این فلگ باعث بازنویسی آدرس و توقف اجرای سایر دستورات rewrite
اما برخلاف last
تطبیق جدیدی با location
ها انجام نمی دهد. بنابراین اگر این فلگ در داخل یک بلاک location
استفاده شده باشد پردازش درخواست درون همان location
ادامه خواهد یافت و تطبیق جدیدی انجام نخواهد شد.
با توجه به مثال بالا اگر آدرس 127.0.0.1:8066/hello-man
را درون مرورگر باز کنیم, اولین rewrite
انجام خواهد شد که باعث میشود باقی rewrite
ها پردازش نشوند. و از آنجایی که تطبیق جدیدی با آدرس بازنویسی شده انجام نمی شود, هیچگاه rewrite
دوم انجام نمیشود و در نهایت درخواست از طریق مسیر /hello-world
پردازش خواهد شد.
استفاده از rewrite بدون فلگ
اگر فلگی مشخص نشده باشد، آدرس بازنویسی میشود اما اجرای سایر rewrite ها متوقف نمیشود. یعنی اگر چندین rewrite داشته باشیم, ابتدا تمامی آنها از بالا به پایین پشت سر هم در صورت تطبیق, اجرا می شوند و اگر در دستورات بعدی پاسخی برگردانده نشود در نهایت Nginx بر اساس آدرس بازنویسی شده، دوباره سعی در تطبیق با یک location مناسب میکند.
در مثال بالا اگر به آدرس /goodbye1
برویم درخواست از مسیر /welcome
برای ما لود خواهد شد. اما اگر به ادرس /goodbye2
برویم متن goodbye
از همان مسیر برایمان درون صفحه نمایش داده میشود.
دستور set
با استفاده از دستور set
میتوان یک متغیر ایجاد کرد و آن را مقداردهی کرد. متغیرها در nginx با علامت دلار $
مشخص میشوند. برای ایجاد متغیر میتوان مانند مثال زیر عمل کرد:
مقدار داخل متغیرها همیشه از نوع متنی در نظر گرفته خواهند شد. در صورتی که مقدار مورد نظر شما دارای کاراکتر فاصله یا ;
باشد, باید مقدار مورد نظر خود را با کوتیشن یا دابل کوتیشن محصور کنید.
دستور if
با استفاده از دستور if میتوان در صورت برقرار بودن یک شرط, کدی را اجرا کرد. ساختار کلی آن به صورت زیر است:
در اینجا condition شرط مورد نظر ما است و در صورتی که برابر با true شود, کدهای درون بدنه if اجرا خواهند شد. (مستندات)
- برای بررسی برابر بودن میتوان از
=
و یا نابرابر بودن از! =
استفاده کرد. - میتوان از
~
و یک Regex برای برابر بودن استفاده کرد. در این حالت به بزرگ یا کوچک بودن حروف حساس است. - میتوان از
*~
و یک Regex برای برابر بودن استفاده کرد. در این حالت به بزرگ و کوچک بودن حروف حساس نیست. - در صورتی که از متغیر استفاده کرد و آن متغیر دارای مقداری نباشد یا دارای
0
باشد از آن به صورت false نتیجه گیری خواهد شد.
در اکثر موارد از چهار حالت بالا برای مقایسه استفاده میکنیم. در مورد حالت های پیچیده تر را میتوانید در مستندات Nginx مطالعه کنید.
با توجه به کد بالا, اگر به آدرس, ?name=
را اضافه کنید و به آن مقدار دهید, آن مقدار درون صفحه نمایش داده میشود. در غیر اینصورت متن hello world
درون صفحه نمایش داده میشود. برای مثال اگر به آدرس 127.0.0.1:8070?name=mahdi
برویم متن Hello mahdi
بر روی صفحه نمایش داده میشود.
در این کد ابتدا یک متغیر با نام $name
تعریف کردیم و با استفاده از $arg_name
مقدار query string که نام آن name باشد را درون این متغیر قرار دادیم. سپس درون بدنه ی location در صورتی که $name
خالی باشد به صورت پیش فرض مقدار world
را درون آن قرار میدهیم. بدین صورت اگر نامی را با استفاده کوئری استرینگ پاس ندهیم Hello world
نمایش داده میشود و در غیر اینصورت Hello
به همراه نام مورد نظر ما بر روی صفحه نمایش داده میشود.
در Nginx یکسری متغیر پیش فرض وجود دارند که میتوانید لیست آنها را درون مستندات ببینید و در صورت نیاز میتوانید مستندات را بررسی کنید و از متغیر دلخواه استفاده کنید.
به کدهایی که در این قسمت بررسی کردیم رو میتونید از طریق رپازیتوری گیت هاب دسترسی داشته باشید.
قسمت قبل: کش (cache) | Nginx from scratch
قسمت بعد: ایجاد پسوورد بر روی یک مسیر | Nginx from scratch