مفاهیم پایه برنامه نویسی وب

این مقاله برای علاقه‌مندانی است که با مفاهیم مقدماتی برنامه نویسی آشنا هستند و می‌خواهند به حوزه برنامه نویسی وب وارد شوند. در این مقاله مفاهیم پایه برنامه نویسی وب (Backend و Frontend)، مفاهیم پایه شبکه، پروتکل های شبکه، سرور ها، نحوه اجرای اپلیکیشن های سمت سرور و ارتباط آنها با کلاینت‌ها و نحوه ارتباط بین اپلیکیشن های سرور شرح داده می‌شود. محتوای هر بخش کوتاه و تنها به قصد آشنایی با موضوع تهیه شده است.

برنامه نویسی وب
برنامه نویسی وب

شبکه های کامپیوتری

شبکه های کامپیوتری برای به اشتراک گذاری منابع (داده، نرم افزار و سخت افزار) ایجاد می‌شوند. با استفاده از یک شبکه می‌توان دو یا چند دستگاه (Device) از جمله کامپیوتر و موبایل را به هم وصل کرد و منابع را بین آنها به اشتراک گذاشت. به هر دستگاه متصل به شبکه گره (Node) گفته می‌شود.

برای ایجاد یک شبکه کامپیوتری از سخت افزار هایی همانند سوییچ (Switch)، مودم (Model)، روتر (Router) و غیره استفاده می‌شود. از آنجایی که در این مقاله تمرکز روی لایه های نرم افزاری می‌باشد، از جزئیات مربوط به سخت افزار های شبکه صرف نظر می‌کنیم.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Computer_network

انواع شبکه های کامپیوتری

شبکه های کامپیوتری از لحاظ گستردگی به دسته هایی همچون PAN، LAN، MAN،‌ WAN و غیره تقسیم می‌شوند.

شبکه های PAN یا Personal Area Network با استفاده تکنولوژی هایی با برد (مسافت) کم مانند بلوتوث، Hotspot گوشی یا مودم های خانگی ایجاد می‌شوند تا وسایل شخصی همچون لپ تاپ و موبایل را در یک شبکه قرار دهد.

شبکه های LAN یا Local Area Network شبکه های خصوصی هستند که در ادارات، شرکت ها، کافی‌نت ها و دیتاسنتر ها رایج هستند.

به همین ترتیب شبکه های MAN و WAN ابعاد بزرگتری مانند یک شهر یا کشور را پوشش می‌دهند.

بیشتر بخوانید:
https://www.belden.com/blogs/network-types

اینترنت

اینترنت شبکه‌ای از شبکه هاست که وسعتی بزرگ تر از کره زمین دارد و طراحی شده تا مردم در سراسر کره زمین بتوانند به وسیله آن با هم در ارتباط باشند از منابع به اشتراک گذاشته شده استفاده کنند.

مهم ترین شبکه های موجود در اینترنت، شبکه های متعلق به دیتاسنتر (Data Center) ها هستند. دیتاسنتر ها سرور های فیزیکی که به اینترنت متصل هستند را به شرکت های نرم افزاری و توسعه دهنده ها ارائه می‌دهند.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Internet
https://en.wikipedia.org/wiki/Data_center

آدرس IP

پس از ایجاد یک شبکه، به هر دستگاه یک آدرس IP (Internet Protocol) اختصاص داده می‌شود. آدرس IP را از جهاتی می‌توان به کد پستی تشبیه کرد و همانطور که کد پستی به یک خانه خاص مرتبط می‌شود،‌ آدرس IP هم به یک Node خاص در شبکه اشاره می‌کند و جهت آدرس‌دهی استفاده می‌شوند.

دستگاه های متصل به شبکه برای ارتباط با یکدیگر از آدرس های IP استفاده می‌کنند. برای مثال در شکل زیر، دو کامپیوتر با IP های 192.168.0.1 و 192.168.0.2 در یک شبکه خصوصی قرار دارند. این دو کامپیوتر با داشتن آدرس IP یکدیگر می‌توانند در آن شبکه با هم ارتباط برقرار کنند.

آدرس IP و ارتباط دو Node در شبکه
آدرس IP و ارتباط دو Node در شبکه

در زمان نوشتن این مقاله، IP در دو نسخه IPv4 و IPv6 وجود دارد. نسخه IPv6 که در سال ۲۰۱۷ به عنوان استاندارد پذیرفته شد در حال رشد می‌باشد، با این وجود هنوز در بیشتر شبکه ها از IPv4 استفاده می‌شود. در این بخش و مثال های این مقاله نیز از نسخه IPv4 استفاده شده است اما ادامه مباحث فارغ از نسخه IP می باشد.

یک IP (نسخه IPv4) از چهار عدد (بین 0 تا 255) که با نقطه جدا شده‌اند تشکیل می‌شود. بیشتر IP ها برای اینترنت استفاده می‌شوند. یک سری از IP ها نیز برای شبکه های خصوصی و loopback رزرو شده‌اند تا تداخلی با IP های اینترنت نداشته باشند.

برای مثال رنج IP های زیر برای استفاده در شبکه های خصوصی رزرو شده‌اند.

  • 192.168.0.0 تا 192.168.255.255
  • 172.16.0.0 تا 172.31.255.255

یک سری از IP ها نیز Loopback نام دارند و به خود Node مبدا اشاره می‌کند. کاربرد این سری از IP های برای تست و ارتباط Node با خودش است. برای ارتباط از طریق این IP ها نیازی به اتصال به اینترنت یا شبکه خصوصی روی Node نیست. معروف‌ترین این IP ها 127.0.0.1 است.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/IP_address
https://en.wikipedia.org/wiki/Reserved_IP_addresses
https://en.wikipedia.org/wiki/Localhost

دامنه (Domain) و DNS

دامنه (Domain) کاربرد های مختلفی در شبکه ها و بخصوص اینترنت دارد. یکی از مهمترین کاربرد آن نامگذاری روی سرویس (یا Node) های موجود در شبکه است. با وجود یک سرور DNS (Domain Name System) در شبکه که همانند یک دفترچه تلفن برای نگاشت بین دامنه ها و IP ها استفاده می‌شود، Node های موجود در شبکه می‌توانند بجای آدرس IP با استفاده از دامنه با هم ارتباط برقرار کنند.

برای مثال در اینترنت، دامنه nic.ir به آدرس آی‌پی 194.225.70.16 اشاره می‌کند. در نتیجه یک نود در اینترنت (برای مثال یک کاربر متصل به اینترنت) به جای ارتباط با 194.225.70.16 می‌تواند با دامنه nic.ir ارتباط برقرار کند. برای مثال شما در مرورگر خود می‌توانید دامنه nic.ir را به جای 194.225.70.16 وارد کنید.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Domain_name
https://en.wikipedia.org/wiki/Domain_Name_System
https://en.wikipedia.org/wiki/Name_server

شماره Port

همانطور که قبلا اشاره شد، یک نود در شبکه با داشتن آدرس IP نود دیگر می‌تواند با آن نود ارتباط برقرار کند. اما اگر بخواهیم دقیق تر به این قضیه نگاه کنیم، باید اصلاح کرد که این ارتباط بین اپلیکیشن های موجود بر روی Node ها صورت می‌پذیرد نه خود Node ها.

هر Node می‌تواند میزبان یک یا چند اپلیکیشن متقاضی ارتباط در شبکه باشد. سیستم عامل هر Node به اپلیکیشن های روی آن Node شماره Port هایی اختصاص می‌دهد. همانند آدرس IP که در یک شبکه متعلق به یک Node است، هر شماره Port در یک Node متعلق به یک اپلیکیشن بر روی آن Node می‌باشد. در نتیجه، هر اپلیکیشن با داشتن آدرس IP نود دیگر و شماره Port اپلیکیشن مورد نظر بر روی آن Node می‌تواند با آن اپلیکیشن ارتباط برقرار کند.

برای مثال در شکل زیر اگر اپلیکیشن A بر روی کامپیوتر C1 بخواهد با اپلیکیشن D بر روی کامپیوتر C2 ارتباط برقرار کند باید آدرس IP کامپیوتر C2 که 192.168.0.2 است و شماره Port اپلیکیشن D که 18 می‌باشد را داشته باشد.

اپلیکیشن ها و پورت ها
اپلیکیشن ها و پورت ها

چنانچه از Loopback IP ها مانند 127.0.0.1 استفاده شود، با استفاده از پورت ها حتی بدون اتصال به شبکه یا اینترنت، اپلیکیشن های روی یک Node هم می‌توانند با هم ارتباط برقرار کنند. برای مثال، در نود C1 اپلیکیشن B می‌تواند با پورت 33 و آدرس آی‌پی 127.0.0.1 با اپلیکیشن C ارتباط برقرار کند. امکان ارتباط این دو اپلیکیشن با استفاده از IP شبکه 192.168.0.1 هم وجود دارد، اما در این صورت اطلاعات برای منتقل شدن از Node خارج و وارد شبکه می‌شود و با مسیریابی شبکه مجددا به خود Node برمی‌گردد که در نتیجه شاهد افت سرعت نسبت به ارتباط از طریق Loopback IP خواهیم بود.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Port_(computer_networking)
https://en.wikipedia.org/wiki/Localhost

آدرس Socket

به ترکیب آدرس IP یا Domain مربوط به یک Node و شماره Port یک اپلیکیشن موجود روی آن Node آدرس Socket گفته می‌شود. آدرس سوکت معمولا بصورت IP:Port (برای مثال 192.168.0.2:18 یا nic.ir:80) نوشته می‌شود. آدرس سوکت به یک اپلیکیشن خاص در شبکه اشاره می‌کند و ارتباط اپلیکیشن های موجود در شبکه با داشتن آدرس سوکت میسر می‌شود.

برای نوشتن اپلیکیشن هایی که می‌خواهند بر روی یک شبکه با هم ارتباط برقرار کنند، می‌توان از زبان های برنامه نویسی که قابلیت برنامه نویسی سوکت (Socket Programming) را ارائه می‌دهند استفاده کرد. از جمله زبان هایی که قابلیت برنامه نویسی سوکت را ارائه می‌دهند، می‌توان به جاوا، PHP، پایتون، Go، سی و ++C اشاره کرد.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Network_socket

مدل کلاینت و سرور

ارتباط بین اپلیکیشن های موجود بر روی شبکه معمولا بصورت درخواست و پاسخ (Request/Response) می‌باشد. برای مثال، اپلیکیشن A میزبان اطلاعات کاربران می‌باشد و اپلیکیشن B مسئول ایجاد کد تخفیف به مناسبت زادروز کاربران است. اپلیکیشن B برای دریافت اطلاعات کاربران می‌تواند یک درخواست به اپلیکیشن A بفرستد و اپلیکیشن A در پاسخ لیست کاربران را برگرداند.

اپلیکیشن درخواست کننده را اپلیکیشن کلاینت (Client Application) و اپلیکیشن پاسخ دهنده (سرویس دهنده) را اپلیکیشن سرور (Server Application) می‌گویند. Node میزبان اپلیکیشن های کلاینت را بطور مختصر کلاینت و Node میزبان اپلیکیشن های سرور را بطور مختصر سرور می‌نامند.

client = new SocketClient()
users = client.send(&quot192.168.0.1:33&quot, &quotGive me the list of users&quot)
// Rest of the process

شبه کد بالا متعلق به اپلیکیشن کلاینت (B) است و به یک زبان فرضی شی‌گرا نوشته شده است. در این شبه کد، یک درخواست با محتوای «Give me the list of users» به سوکت 192.168.0.1:33 (اپلیکیشن A) فرستاده می‌شود و پس از دریافت پاسخ، آنرا در متغیر users می‌ریزد.

server = new SocketServer()
server.listen(33, function(request) {
    switch (request) {
        case &quotGive me the list of users&quot:
            return UserRepository.all().toJson()
        else:
            return &quotBad Request&quot
    }
})

شبه کد بالا متعلق به اپلیکیشن سرور (A) است که روی یک Node با آدرس 192.168.0.1 در حال اجرا است. این اپلیکیشن به Port شماره 33 گوش می‌دهد و با دریافت هر درخواست، تابع (Function) پردازش درخواست را فراخوانی می‌کند. در تابع مربوطه، با توجه به محتوای درخواست، پاسخ مناسب بازگردانده می‌شود.

مدل کلاینت و سرور در طراحی سیستم های مبتنی بر اینترنت، شبکه های خصوصی و برای ارتباط اپلیکیشن های روی یک Node کاربرد دارد. مثالی از این مدل سرویس های تلگرام، اینستاگرام و ... می‌باشد که اپلیکیشن کلاینت همان نسخه اندروید، iOS و وب می‌باشد که کاربر نصب می‌کند و اپلیکیشن سرور بر روی سرور سرویس مورد نظر اجرا شده و به اپلیکیشن های کلاینت سرویس می‌دهد. مثالی دیگر از این مدل، ارتباط یک اپلیکیشن نصب شده روی سرور (اینبار بعنوان اپلیکیشن کلاینت!) با یک پایگاه داده (Database) مانند MySQL (بعنوان اپلیکیشن سرور) می‌باشد که بواسطه این ارتباط اپلیکیشن می‌تواند داده ها را در دیتابیس ذخیره یا بخواند.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Client%E2%80%93server_model

پروتکل

در مثال اپلیکیشن های کلاینت و سرور در بخش قبل، کلاینت پیغام «Give me the list of users» را به اپلیکیشن سرور می‌فرستد و اپلیکیشن سرور نیز به گونه‌ای طراحی شده که با دریافت درخواستی با این محتوا، لیست همه کاربران را بعنوان پاسخ بازگرداند. به بیان دقیق‌تر، قراردادی ایجاد شده که هر دو اپلیکیشن های کلاینت و سرور آنرا متوجه می‌شوند. در این قرارداد، درخواستی با محتوای «Give me the list of users» برای دریافت لیست همه کاربران تعریف شده است. به قرارداد هایی که تعریف می‌شوند تا اپلیکیشن های کلاینت و سرور طبق آن با هم ارتباط برقرار کنند، پروتکل (Protocol) می‌گویند.

در صورتی که شما توسعه دهنده اپلیکیشن های کلاینت و سرور باشید، به دلخواه خود می‌توانید پروتکل را تعریف کنید. در واقعیت بسیاری از امکانات طراحی شده بر روی شبکه ها همچون وب، ایمیل و SSH، بصورت عمومی تعریف می‌شوند و اپلیکیشن های متفاوتی توسط شرکت های مختلفی برای آنها پیاده‌سازی می‌شود. در این صورت لازم است تا پروتکل های استانداردی تعریف شود و همه تولیدکنندگان اپلیکیشن طبق آن عمل کنند.

برای نمونه یکی از امکانات مفیدی که با استفاده از شبکه ایجاد شده ایمیل می‌باشد. پروتکل SMTP برای ارسال ایمیل مورد استفاده قرار می‌گیرد. برای اینکه به شخصی ایمیل بفرستید، باید بر روی یک نود از شبکه، یک اپلیکیشن (همانند Gmail) داشته باشید که با استفاده از پروتکل SMTP بتواند متن ایمیل را به سوکت مقصد (ارائه دهنده سرویس ایمیل مخاطب مانند Gmail یا Yahoo) ارسال کند.

یک پروتکل فرضی برای ارسال ایمیل می‌تواند به شکل زیر باشد:

درخواست:

Email Sending Protocol v1.0
From: info@miladrahimi.com
To: jack@example.com
Message: &quotHello Jack!&quot

پاسخ:

Result: OK

بیشتر بخوایند:
https://www.manageengine.com/network-monitoring/network-protocols.html
https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol

وب

یکی از کاربرد های شبکه و بخصوص اینترنت وب می‌باشد. وب بر پایه دو پروتکل HTTP و HTTPS ایجاد شده است. کاربرد این پروتکل ها، دریافت و ارسال صفحات وب (HTML)، انواع فایل ها، انواع اطلاعات در فرمت های مختلف همانند JSON و XML و ... می‌باشد.

تفاوت دو پروتکل HTTP و HTTPS تنها وجود رمزنگاری در HTTPS است. به این صورت که در HTTPS، درخواست از سمت کلاینت رمزنگاری و در سمت سرور رمزگشایی می‌شود. پاسخ HTTP نیز در سمت سرور رمزنگاری و در سمت کلاینت رمزگشایی می‌شود.

در سمت سرور، اپلیکیشن سرور قرار دارد که سرویس مربوطه را ارائه می‌دهد. در مورد دریافت و ارسال صفحات وب (HTML)، اپلیکیشن کلاینت می‌تواند یکی از مرورگر های معروف مانند Chrome یا Firefox باشد. در مورد دریافت و ارسال اطلاعات با فرمت JSON، کلاینت می‌تواند یک اپلیکیشن موبایل، دسکتاپ یا اسکریپت داخلی یک صفحه وب باشد. در مورد دریافت و ارسال فایل، کلاینت می‌تواند یک مرورگر یا دانلود منیجر باشد.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/World_Wide_Web
https://en.wikipedia.org/wiki/HTTPS

دریافت و ارسال HTML

ارسال و دریافت صفحات وب (HTML) یکی از امکانات وب است. در سمت کلاینت معمولا از مرورگر های وب مانند Chrome و Firefox استفاده می‌شود. در سمت سرور اپلیکیشن ارائه دهنده سرویس (وب‌سایت) قرار دارد.

بیشتر وبسایت ها از تعدادی صفحه وب (HTML) تشکیل شده‌اند. این صفحه ها با درخواست HTTP کاربر از طریق کلاینت های HTTP همچون مرورگر ها، در اختیار کاربر قرار می‌گیرند. بعضی از این صفحات یک کد HTML ثابت و برخی با توجه به درخواست ورودی و بعد از پردازش آن، کد HTMLی را تولید و به کاربر می‌دهند.

برای مثال، اگر شما در مرورگر سایت https://google.com را درخواست کنید. مرورگر شما یک درخواست HTTPS (همان HTTP رمزنگاری شده) به سرور گوگل با دامنه google.com و پورت 443 (پورت پیشفرض برای پروتکل HTTPS) می‌فرستد. سرور گوگل با دریافت درخواست، صفحه HTML مربوط به صفحه اصلی (خانه) خود را بعنوان پاسخ HTTP به مرورگر می‌فرستد.

درخواست و پاسخ HTTP بین مرورگر و سرور
درخواست و پاسخ HTTP بین مرورگر و سرور

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Web_browser
https://en.wikipedia.org/wiki/HTML

آدرس صفحات وب

صفحات وب (و فایل ها) با URL (کوتاه شده‌ی Uniform Resource Locator) آدرس دهی می‌شوند. مرورگر ها، کلاینت های وب همچون cURL و کتابخانه های برنامه نویسی معمولا URL را بعنوان ورودی برای دسترسی به یک فایل یا صفحه وب در اینترنت دریافت می‌کنند. ساختار یک URL ساده (بدون اطلاعات هویت) بصورت زیر است:

scheme://host/[path][?query]

برای مثال:

https://shop.com/products?id=13
http://example.com:33/page.html

در این ساختار:

  • بخش scheme پروتکل را مشخص می‌کند که می‌تواند http یا https باشد.
  • بخش host دامنه یا IP و Port را مشخص می‌کند.
  • بخش path آدرس صفحه یا سرویس داخلی را مشخص می‌کند.
  • بخش query پارامتر های ورودی مورد نیاز صفحه یا سرویس داخلی را مشخص می‌کند.

در صوتی که در بخش host تنها دامنه یا IP وارد شود، اپلیکیشن کلاینت (مرورگر) بطور پیشفرض پورت 80 را برای پروتکل HTTP و پورت 443 را برای پروتکل HTTPS در نظر می‌گیرد. برای مثال دو آدرس زیر یکسان می‌باشند و مرورگر host اولی را بطور پیشفرض با پورت 443 درنظر می‌گیرد.

https://miladrahimi.com/pay.html
https://miladrahimi.com:443/pay.html

به همین خاطر معمولا اپلیکیشن های سمت سرور که سرویس وب را ارائه می‌دهند طوری طراحی می‌شوند که به پورت های 80 و 443 گوش کنند.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/URL
https://en.wikipedia.org/wiki/Uniform_Resource_Identifier

پروتکل HTTP

همانطور که قبلا اشاره شد برای وب از پروتکل HTTP (یا نسخه رمزنگاری شده آن HTTPS) استفاده می‌شود. در زیر یک درخواست HTTP که مرورگر به هنگام وارد شدن آدرس http://miladrahimi.com/pay.html به مقصد miladrahimi.com:80 می‌فرستند را مشاهده می‌کنید.

GET /pay.html HTTP/1.1
Host: miladrahimi.com

درخواست HTTP دارای دو قسمت Header و Body است (با تگ های head و body در HTML اشتباه نگیرید) که با یک خط خالی جدا می‌شوند. در خواست فوق تنها Header دارد و فاقد بخش Body می‌باشد.

در خط اول این درخواست HTTP:

  • عبارت GET متد درخواست است. متد های مختلف طراحی شده‌اند تا بتوانند از یک URL برای کاربرد های مختلفی استفاده کنند. متد درخواست هایی که مرورگر پس از وارد شدن URL توسط کاربر ایجاد می‌کند GET است.
  • عبارت pay.html/ مسیر (Path) درخواست است که معادل Path مربوط به URL است.
  • عبارت HTTP/1.1 نسخه پروتکل را مشخص می‌کند.

خط دوم از Header درخواست بصورت Key: Value نوشته شده است. در این درخواست یک Host وجود دارد که برابر miladrahimi.com می‌باشد. هدر Host به این دلیل لازم می‌باشد که ممکن است اپلیکیشن سرور، سرویس های مختلفی را از طریق چند دامنه متفاوت ارائه دهد و نیاز داشته باشد بداند درخواست HTTP دریافتی برای کدام دامنه بوده است.

اپلیکیشن کلاینت (مرورگر) می‌تواند در خط های بعدی Header، اطلاعات دیگری همانند نام و نسخه خودش، سیستم عامل کاربر و ... را در درخواست بگنجاند.

در زیر پاسخ HTTP که اپلیکیشن سرور miladrahimi.com:80 بعنوان پاسخ به درخواست HTTP فوق برمی‌گرداند را می‌بینید.

HTTP/1.1 200 OK
Content-type: text/html

<html>
...
</html>

همانند درخواست HTTP، پاسخ HTTP نیز دارای دو قسمت Header و Body است که با یک خط خالی جدا می‌شوند. در قسمت Header اطلاعات مربوط به نوع و محتوای پاسخ و در قسمت Body محتوای پاسخ (کد HTML صفحه یا محتوای فایل) قرار می‌گیرد.

در مثال بالا عبارت HTTP/1.1 نسخه پروتکل را نشان می‌دهد. عدد 200 کد وضعیت و عبارت OK نام وضعیت پاسخ است. در زیر لیست وضعیت های پر استفاده HTTP را می‌بینید.

  • 200 OK (سرور درخواست کاربر را با موفقیت پاسخ می‌دهد)
  • 204 No Content (سرور با موفقیت درخواست را انجام داده اما محتوایی برای بازگرداندن ندارد)
  • 301 Moved Permanently (منبع مورد نظر برای همیشه به آدرس دیگری منتقل شده)
  • 303 See Other (سرور از کلاینت می‌خواد در ادامه به آدرس دیگری رجوع کند)
  • 400 Bad Request (درخواست کاربر دارای مشکل است)
  • 401 Unauthorized (سرور قادر به تشخیص کاربر درخواست کننده نیست)
  • 403 Forbidden (کاربر دسترسی لازم برای مشاهده منبع را ندارد)
  • 404 Not Found (منبع یا صفحه مورد نظر وجود ندارد)
  • 500 Internal Error (سرور با خطای داخلی مواجه شده و قادر به پاسخ دادن نیست)

بخش Body پاسخ حاوی کد HTML صفحه وب درخواست شده است که اگر کلاینت یک مرورگر باشد، آن را Render می‌کند و خروجی را به کاربر نمایش می‌دهد. در صورتی صفحه HTML حاوی Asset (فایل های CSS، جاوااسکریپت، تصویر، ویدیو و ...) باشد، به ازای هر کدام از آنها، مرورگر یک درخواست مشابه به سرور می‌فرستد تا بعنوان پاسخ محتوای هر یک را دریافت کند و در پروسه Render، آنها را لحاظ کند.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
https://en.wikipedia.org/wiki/HTTPS
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

کوکی (Cookie)

یکی از امکاناتی که در مرورگر ها و برخی از کلاینت های وب (HTTP) پیاده سازی شده، پشتیبانی از کوکی (Cookie) است. کوکی بصورت یک پایگاه داده Key/Value است که از طرف اپلیکیشن کلاینت (مرورگر) در اختیار سایت ها قرار می‌گیرد.

اپلیکیشن سرور با قراردادن هدر مربوط به کوکی در پاسخ های HTTP می‌تواند به اپلیکیشن کلاینت خبر دهد که اطلاعات مورد نیازش را ذخیره کند. اپلیکیشن کلاینت اگر از کوکی ها پشتیبانی کند، اطلاعات دریافتی را ذخیره و در درخواست های HTTP بعدی آنرا در Header درخواست می‌گنجاند.

نمونه از یک پاسخ HTTP از اپلیکیشن سمت سرور که نیاز به ذخیره اطلاعات در کوکی دارد:

HTTP/1.1 200 OK
Set-Cookie: name=Jack; Max-Age=86400
Set-Cookie: id=33; Max-Age=86400

<html>...</html>

پاسخ HTTP فوق از اپلیکیشن سمت سرور به کلاینت خبر می‌دهد که دو داده مورد نظر را در سمت کلاینت بعنوان کوکی و هر کدام را به مدت ۲۴ ساعت (86400 ثانیه) ذخیره کند. در صورت پشتیبانی اپلیکیشن کلاینت از کوکی، در تمامی درخواست های بعدی تا مدت ۲۴ ساعت، داده های دریافتی برای آن سرور فرستاده می‌شود.

در زیر می‌توانید نمونه یک درخواست HTTP که حاوی داده های کوکی دریافتی است را ببینید:

GET /profile HTTP/1.1
Host: example.com
Cookie: name=Jack; id=33

مهمترین کاربرد کوکی، احراز هویت کاربران است. در سمت اپلیکیشن سرور ممکن است درخواست های گوناگونی از کاربران مختلف دریافت شود. اپلیکیشن سرور با استفاده از کوکی می‌تواند کاربر درخواست کننده را تشخیص دهد.

بیشتر بخوایند:
https://en.wikipedia.org/wiki/HTTP_cookie

لاگین کاربران با Cookie

اکنون با استفاده از مفاهیم شرح داده شده، درخواست و پاسخ های HTTP مربوط به لاگین کاربران در یک سایت فرضی را بررسی می‌کنیم.

در زیر نمونه درخواست با پروتکل HTTP از طرف مرورگر بعد از وارد شدن آدرس http://example.com/login توسط کاربر را می‌بینید:

GET /login HTTP/1.1
Host: example.com

این درخواست HTTP اولین درخواست کاربر به example.com:80 است و به همین خاطر هنوز هیچ کوکی در مرورگر ذخیره نشده و درخواست خالی از کوکی می‌باشد.

نمونه پاسخ HTTP سایت example.com برای درخواست صفحه خانه از سایت:

HTTP/1.1 200 OK

<html>
    <head><title>Example Login</title></head>
    <body>
        <form action=&quot/login&quot method=&quotPOST&quot>
            <input type=&quottext&quot name=&quotusername&quot>
            <input type=&quotpassword&quot name=&quotpassword&quot>
            <button type=&quotsubmit&quot>Login</button>
        </form>
    </body>
</html>

پاسخ HTTP بالا حاوی Header مربوط به وضعیت موفق و Body محتوای HTML صفحه لاگین است. کاربر هنوز در سایت لاگین نکرده و در نتیجه سایت اطلاعاتی جهت ذخیره در کوکی ندارد.

مرورگر با دریافت این پاسخ آنرا که یک فرم ورود (لاگین) است به کاربر نمایش می‌دهد. با وارد شدن Username و Password به ترتیب admin و secret توسط کاربر و کلیک بر دکمه Login که دکمه submit فرم ‌می‌باشد، مرورگر درخواست HTTP زیر را به اپلیکیشن سرور می‌فرستد:

POST /login HTTP/1.1
Host: example.com
username=admin&password=secret

در مثال های قبلی، همیشه درخواست مرورگر با وارد شدن URL توسط کاربر ایجاد می‌شد و مرورگر بطور پیشفرض متد درخواست را GET در نظر می‌گرفت. اینبار درخواست به خاطر کلیک بر دکمه Login فرم موجود در صفحه وب ایجاد شده است. در چنین حالتی مرورگر متد درخواست را از method تگ form که در اینجا POST است انتخاب می‌کند. مسیر (Path) مربوط به درخواست نیز از action مربوط به تگ form انتخاب می‌شود. در خط سوم درخواست، مرورگر اطلاعات وارد شده توسط کاربر در فیلد های فرم را قرار می‌دهد.

درخواست HTTP فوق و درخواستی قبلی دارای URL یکسان (http://example.com/login) می‌باشند اما تفاوت متد آن هاست که در درخواست قبلی متد GET و در خواست فوق متد POST می‌باشد. رفتار اپلیکیشن سرور برای متد های مختلف همانند این مثال می‌تواند متفاوت باشد.

با فرض درست بودن Username و Password، از طرف اپلیکیشن سرور (سایت)، چنین پاسخی دریافت می‌شود:

HTTP/1.1 303 See Other
Location: http://example.com/profile
Set-Cookie: user_id=13; Max-Age=86400

کد پاسخ فوق 303 به معنی نیاز به Redirect کردن کاربر به یک صفحه جدید است. در واقع اپلیکیشن سرور به مرورگر خبر می‌دهد که کاربر را باید به صفحه جدیدی که آدرس آنرا در خط دوم Header می‌بینید منتقل کند. این پاسخ علاوه بر اطلاعات مربوط به انتقال کاربر، حاوی اطلاعاتی برای ذخیره در کوکی (ID کاربر در سرور) نیز می‌باشد.

مرورگر با دریافت پاسخ فوق، کوکی دریافتی را ذخیره و درخواست جدیدی برای دریافت صفحه http://example.com/profile می‌فرستد (کاربر Redirect می‌شود). این درخواست حاوی کوکی دریافتی نیز می‌باشد.

GET /profile HTTP/1.1
Host: example.com
Cookie: user_id=13

اپلیکیشن سمت سرور با دریافت درخواست فوق، متوجه می‌شود که باید صفحه پروفایل مربوط به کاربر با ID=13 را به کلاینت بدهد. پاسخ اپلیکیشن سرور به درخواست به این صورت می‌باشد:

HTTP/1.1 200 OK

<html>
    <head><title>Profile</title></head>
    <body>
        <p>Username: admin</p>
        <p>Full Name: Milad Rahimi</p>
    </body>
</html>

معمولا برای طراحی اپلیکیشن های سمت سرور از زبان و تکنولوژی هایی مانند PHP، جاوا، Node.js، پایتون، Go، سی‌شارپ و ... استفاده می‌شود.

سورس کد مربوط به اپلیکیشن سرور مثال بالا به زبان Go (با استفاده از فریم ورک Echo) به این صورت می‌باشد:

package main

import (
   &quotfmt&quot
   &quotgithub.com/labstack/echo/v4&quot
   &quotnet/http&quot
   &quotstrconv&quot
)

func main() {
   // New instance of echo framework to handle HTTP requests
   e := echo.New()

   // Login (GET)
   e.GET(&quot/login&quot, func(c echo.Context) error {
      return c.HTML(200, &quot<html><form>...</form></html>&quot)
   })

   // Login (POST)
   e.POST(&quot/login&quot, func(c echo.Context) error {
      username := c.FormValue(&quotusername&quot)
      password := c.FormValue(&quotpassword&quot)

      user, err := findByUserPass(username, password)
      if err != nil {
         return c.HTML(401, &quot<html><p>Authorization failed.<p></html>&quot)
      }

      c.SetCookie(&http.Cookie{
         Name:   &quotuser_id&quot,
         Value:  user.ID,
         MaxAge: 86400,
      })
      return c.Redirect(303, &quothttp://example.com/profile&quot)
   })

   // Profile (GET)
   e.GET(&quot/profile&quot, func(c echo.Context) error {
      id, err := c.Cookie(&quotuser_id&quot)
      if err != nil {
         return c.HTML(401, &quot<html><p>Authorization failed.<p></html>&quot)
      }

      user, err := findById(id.Value)
      if err != nil {
         return c.HTML(401, &quot<html><p>Authorization failed.<p></html>&quot)
      }

      html := fmt.Sprintf(
         &quot<html>...<p>Username: %s</p><p>Full Name: %s</p>...</html>&quot,
         user.Username,
         user.FullName,
      )
      return c.HTML(200, html)
   })

   // Start listening to Port 80 (0.0.0.0:80)
   e.Start(&quot:80&quot)
}

جلسه (Session)

در اپلیکیشن سروری که با استفاده از Cookie برای لاگین کاربران طراحی شد، کاربر با استفاده از اطلاعات ذخیره شده در کوکی تشخیص داده می‌شد. اپلیکیشن کلاینت که در سمت کلاینت است،‌ می‌تواند کوکی متفاوتی برای سرور بفرستد. برای مثال در بالا بجای 13 عدد 33 را بفرستد و آنگاه می‌تواند پروفایل کاربر با ID=33 را ببیند و از طرف او با اپلیکیشن سرور در تعامل باشد و در واقع جعل هویت کند.

برای حل مشکل امنیتی احراز هویت کاربر با استفاده از کوکی ها، مکانیزم دیگری بعنوان Session استفاده می‌شود. در این مکانیزم اپلیکیشن سمت سرور، بجای ذخیره اطلاعات مورد نیاز (مثلا ID کاربر) در Cookie، آنرا در یک فایل با نامی رندوم و طولانی (غیر قابل حدس توسط کاربران) در سرور ذخیره می‌کند و تنها نام فایل را در کوکی ذخیره می‌کند. با این مکانیزم کاربر تنها نام Session را در اختیار دارد و بخاطر طولانی و رندوم بودن آن با تغییر آن نمی‌تواند به Session کاربر دیگری دست پیدا کند.

نمونه پاسخ HTTP اپلیکیشن سمت سرور پس از لاگین موفق کاربر:

HTTP/1.1 303 See Other
Location: http://example.com/profile
Set-Cookie: session=1a2b3c...x4v03d; Max-Age=86400

در درخواست های بعدی که مرورگر اطلاعات کوکی را برای اپلیکیشن سرور میفرستد، اپلیکیشن سمت سرور نام فایل سشن را از کوکی دریافتی پیدا می‌کند و اطلاعات کاربر را از فایل ذخیره شده در سمت سرور می‌خواند.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Session_(computer_science)

جاوا اسکریپت و AJAX

جاوا اسکریپت (JavaScript) یک زبان برنامه نویسی چند منظوره می‌باشد. اولین و مهمترین کاربرد این زبان، قابلیت اجرا شدن در مرورگر می‌باشد. کد های JavaScript می‌تواند در میان تگ script در HTML قرار بگیرد تا مرورگر آنرا اجرا کند. هدف از اجرای کد های JavaScript، تغییر تگ های HTML بعد از Load شدن در مرورگر و تعامل با اپلیکیشن سرور می‌باشد.

قابلیت تعامل با اپلیکیشن سرور در JavaScript را AJAX می‌گویند. در شکل زیر نحوه این تعامل در کنار درخواست و پاسخ های HTTP را می‌بینید.

تعامل جاوا اسکریپت با اپلیکیشن سرور (AJAٓX)
تعامل جاوا اسکریپت با اپلیکیشن سرور (AJAٓX)

در توضیح فرایند بالا، مرورگر پس از وارد شدن URL ذکر شده (http://example.com/page.html) توسط کاربر، یک درخواست HTTP به اپلیکیشن سرور می‌فرستند. اپلیکیشن سرور در پاسخ، صفحه HTML که حاوی کد JavaScript است را به مرورگر کاربر می‌فرستد. مرورگر پس از دریافت پاسخ، صفحه HTML را به کاربر نمایش می‌‌دهد. مرورگر علاوه بر نمایش HTML، کد های JavaScript را نیز اجرا می‌کند. کد JavaScript خود می‌تواند به اپلیکیشن سرور درخواست HTTP بفرستد و پاسخ آنرا دریافت کند و بر اساس پاسخ دریافتی ممکن است تگ های HTML را تغییر دهد. مرورگر برخلاف زمانی که خود درخواست می‌فرستند، با درخواست های HTTP که JavaScript می‌فرستند صفحه را از نو render نمی‌کند و حتی ممکن است کاربر نهایی متوجه این تعامل نشود.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/JavaScript
https://en.wikipedia.org/wiki/Ajax_(programming)

وب سرویس های مبتنی بر API

نوعی دیگر از سرویس های وب، سرویس های مبتنی بر API می‌باشد. API ها نیز همانند صفحات وب دارای URL می‌باشند با این تفاوت که محتوای (Body) پاسخ های آنها به جای HTML حاوی فرمت های مناسب انتقال اطلاعات همانند JSON و XML است و درخواست های HTTP به جای مقادیر فیلد ها در Header دارای Body حاوی محتوایی با فرمت های مناسب انتقال اطلاعات می‌باشد. اپلیکیشن کلاینت برای صفحات وب معمولا مرورگر ها می‌باشند ولی اپلیکیشن کلاینت برای API ها می‌تواند اسکریپت های JavaScript، اپلیکیشن های موبایل و حتی دیگر اپلیکیشن های سرور باشد.

برای مثال، در زیر یک درخواست HTTP به یک API را مشاهده می‌کنید:

GET /api/products HTTP/1.1
Host: shop.com

و در زیر پاسخ HTTP مربوط به درخواست فوق است که محتوای با فرمت JSON می‌باشد:

HTTP/1.1 200 OK

[
    {&quotid&quot: 1, &quotname&quot: &quotMacBook Pro&quot, &quotprice&quot: 1200},
    {&quotid&quot: 2, &quotname&quot: &quotiPhone 13&quot, &quotprice&quot: 980}
]

فرمت های انتقال اطلاعات همچون JSON و XML فرمت هایی مناسب برای پردازش توسط اپلیکیشن ها می‌باشد. برای مثال محتوای (JSON) فوق، لیستی از محصولات را نشان ‌می‌دهد که شامل دو محصول و هر محصول داری سه ویژگی id, name و price می‌باشد. بیشتر زبان ها و تکنولوژی های برنامه‌نویسی دارای ابزاری برای خواندن و نوشتن اطلاعات با چنین فرمت هایی هستند.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Web_service
https://en.wikipedia.org/wiki/Web_API
https://en.wikipedia.org/wiki/JSON
https://en.wikipedia.org/wiki/XML

وب اپلیکیشن

وب اپلیکیشن ها به نوعی از وب سایت ها می‌گویند که معمولا دارای یک صفحه HTML حاوی یک اسکریپت JavaScript هستند و بجز درخواست HTTP مربوط به دریافت HTML، بقیه درخواست ها توسط جاوا اسکریپت به API های اپلیکیشن سرور فرستاده می‌شوند.

معمولا برای طراحی وب اپلیکیشن ها از فریم ورک های JavaScript همچون Vue.js، React.js و Angular استفاده می‌کنند. نسخه وب واتساپ و اینستاگرام نمونه های از وب اپلیکیشن می‌باشد.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Web_application
https://en.wikipedia.org/wiki/Single-page_application
https://en.wikipedia.org/wiki/Progressive_web_application

اصول REST

برای طراحی API های یک اپلیکیشن سرور که پاسخ درخواست های یک وب اپلیکیشن (یا اپلیکیشن موبایل یا دیگر اپلیکیشن های سرور) را می‌دهد، معمولا از اصول REST استفاده می‌شود. API و وب اپلیکیشنی که بر اساس اصول REST طراحی شده باشد، RESTful نامیده می‌شود. برخی از اصول REST عبارت‌اند از:

  • استفاده از پروتکل HTTP(S)
  • استفاده از مدل کلاینت و سرور
  • استفاده مفهومی از کد های وضعیت HTTP برای کاربرد های مختلف
  • استفاده مفهومی از متد های HTTP برای کاربرد های مختلف

برای مثال، در زیر لیستی از API های RESTful برای مدیریت محصولات یک فروشگاه را مشاهده می‌کنید:

# List of products
Method=GET, URL=http://shop.com/api/products

# Create a new product
Method=POST, URL=http://shop.com/api/products

# Get a single product information (product id = 13)
Method=GET, URL=http://shop.com/api/products/13

# Update a single product (product id = 13)
Method=PUT, URL=http://shop.com/api/products/13

# Delete a single product (product id = 13)
Method=DELETE, URL=http://shop.com/api/products/13

برای مثال درخواست HTTP مربوط به ساخت یک محصول به شکل زیر است:

POST /api/products HTTP/1.1
Host: shop.com

{&quottitle&quot: &quotiPhone 7 Plus&quot, &quotprice&quot: 449}

و پاسخ HTTP مربوط به درخواست فوق در صورتی که با موفقیت انجام شود به شکل زیر می‌باشد:

HTTP/1.1 201 Created

{
    &quotmessage&quot: &quotThe product created successfully.&quot,
    &quotproduct&quot: {&quotid&quot: 33, &quottitle&quot: &quotiPhone 7 Plus&quot, &quotprice&quot: 449}
}

اگر مشکلی در اجرای دستور پیش بیاید، برای مثال فرضا عنوان محصولات می‌بایست منحصربفرد باشد و قبلا محصولی با عنوان مورد نظر موجود باشد، پاسخ به شکل زیر می‌باشد:

HTTP/1.1 422 Unprocessable Entity

{
    &quoterrors&quot: [
        {&quottitle&quot: [&quotThe title must be unique.&quot]}
    ],
}

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Representational_state_transfer

احراز هویت با توکن

پیش‌تر روش احراز هویت کاربران با استفاده از Cookie و Session را که مناسب وب‌سایت های ساده و قدیمی بود شرح داده شد. یک روش مناسب برای احراز هویت کاربران برای وب اپلیکیشن ها، موبایل اپلیکیشن ها و API های بین دو اپلیکیشن سرور، استفاده از توکن (Token) می‌باشد.

در احراز هویت با استفاده از توکن، پس از لاگین موفق، اپلیکیشن سرور یک رشته طولانی از حروف و اعداد رندوم و منحصر بفرد برای کاربر تولید می‌کند و در پاسخ HTTP برای کاربر می‌فرستد. اپلیکیشن کلاینت کاربر در درخواست های بعدی که فراخوانی API های نیازمند احراز هویت می‌باشد، توکن دریافت شده را در Header درخواست جای می‌دهد و اپلیکیشن سرور از روی توکن ارسال شده، کاربر را تشخیص می‌دهد.

در زیر می‌توانید یک نمونه درخواست HTTP برای لاگین کاربر را ببینید.

POST /api/auth/login HTTP/1.1
Host: shop.com

{&quotusername&quot: &quotmilad&quot, &quotpassword&quot: &quot12345678&quot}

پاسخ HTTP درخواست فوق در صورتی که اطلاعات ورود صحیح باشد:

HTTP/1.1 200 OK

{
    &quottoken&quot: &quotf93n1mM24Eh1b8nWXf9NJrkay3GgQtea&quot,
    &quotuser&quot: {
        &quotusername&quot: &quotmilad&quot,
        &quotemail&quot: &quotinfo@miladrahimi.com&quot,
        &quotname&quot: &quotMilad Rahimi&quot
    }
}

پاسخ HTTP درخواست لاگین در صورتی که اطلاعات ناموفق باشد:

HTTP/1.1 401 Unauthorized

پاسخ فوق می‌تواند حاوی یک Body با فرمت JSON و پیام خطا باشد ولی اگر بخواهیم مینیمال فکر کنیم نیازی به Body ندارد و کد 401 کافی است!

اکنون درخواست HTTP مربوط به ساخت یک محصول را که قبلا در بخش اصول REST مشاهده کردید را با در نظر گرفتن احراز هویت با توکن بازنویسی می‌کنیم.

POST /api/products HTTP/1.1
Host: shop.com
Authorization: f93n1mM24Eh1b8nWXf9NJrkay3GgQtea

{&quottitle&quot: &quotiPhone 7 Plus&quot, &quotprice&quot: 449}

همانطور که در درخواست فوق قابل مشاهده است، توکن در هدر Authorization جای داده می‌شود. اپلیکیشن سرور با دریافت این درخواست می‌تواند کاربر درخواست کننده را تشخیص دهد. در صورتی که توکن موجود در درخواست اشتباه یا به هر دلیلی اپلیکیشن سرور قادر به تشخیص کاربر از روی آن نباشد، اپلیکیشن سرور می‌تواند خطای 401 Unauthorized را به اپلیکیشن کلاینت بازگرداند. اپلیکیشن کلاینت نیز بهتر است طوری طراحی شود که با دریافت این خطا به کاربر فرم لاگین رو نمایش دهد تا فرایند احراز هویت (لاگین) از سر گرفته شود.

وب سایت های استاتیک

وب‌سایت های استاتیک به وب‌سایت هایی گفته می‌شود که از تعدادی فایل HTML و Asset های مورد نیاز آن همانند فایل های CSS و JavaScript و فایل های معمولی مانند تصاویر، ویدیو ها، فایل های صوتی و ... تشکیل شده است. در این وب سایت ها، هر درخواست HTTP از طرف کلاینت به یک فایل در سرور منتهی می‌شود و اپلیکیشن سرور تنها مسئول ارائه دادن محتوای فایل ها به کلاینت است. همانطور که مشخص است، در این وب‌سایت ها پردازش درخواست و لایه Logic وجود ندارد.

برای راه اندازی یک وب‌سایت استاتیک نیازی به نوشتن اپلیکیشن سرور نیست. یک وب سرور مانند NGINX می‌تواند نیاز شما را برطرف کند. در زیر کانفیگ NGINX مربوط به یک وب‌سایت استاتیک را مشاهده می‌کنید:

server {
    listen 80;
    server_name example.com;
    location / {
        root /web;
        index index.html;
    }
}

کانفیگ بالا، تعریف یک سرور (وب‌سایت) در NGINX است. وب‌سایت مورد نظر به پورت 80 و دامنه example.com گوش می‌کند (example.com:80). به ازای هر درخواستی که Path آن با / شروع می‌شود (یعنی تمامی درخواست ها)، NGINX به دنبال فایلی با مسیر مطابق با Path در دایرکتوری web/ می‌گردد، اگر فایل مورد نظر وجود داشت آنرا بعنوان پاسخ به کلاینت می‌دهد، اگر وجود نداشت خطای 404 Not Found را برمی‌گرداند و اگر مسیر مورد نظر یک دایرکتوری باشد نه یک فایل، به دنبال فایلی با نام index.html درون آن دایرکتوری می‌گردد. در زیر لیستی از URL ها و فایل هایی که NGINX به ازای آن بر می‌گرداند را می‌توانید مشاهده کنید.

URL: http://example.com/images/the_persistence_of_memory.jpg
Path: /images/the_persistence_of_memory.jpg
Type: File
File: /web/images/the_persistence_of_memory.jpg

URL: http://example.com/images
Path: /images
Type: Directory
File: /web/images/index.html

URL: http://example.com/
Path: /
Type: File
File: /web/index.html

بیشتر بخوانید:
https://en.wikipedia.org/wiki/Static_web_page

وب سایت های PHP

این بخش مخصوص علاقه‌مندانی است که می‌خواهند از زبان PHP برای ساخت اپلیکیشن سمت سرور استفاده کنند.

در زبان PHP امکاناتی برای کار با سوکت و هندل کردن درخواست های HTTP وجود دارد اما متاسفانه استفاده از آنها برای سرویس های واقعی (غیر تستی) پیشنهاد نمی‌شود. برای حل این مشکل در کنار PHP از یک وب سرور مانند NGINX یا Apache HTTP Server استفاده می‌شود.

کامپایلر PHP در دو نسخه CLI و FPM منتشر می‌شود. نسخه CLI مخصوص نوشتن اپلیکیشن های خط فرمان و نسخه FPM مخصوص نوشتن اپلیکیشن های سرور است و ما در اینجا به نسخه FPM آن نیاز داریم. نسخه FPM بطور پیشفرض به پورت 9000 گوش می‌کند و وب سرور ها با استفاده از این پورت می‌توانند با PHP ارتباط برقرار کنند و فایل های PHP را کامپایل کنند تا خروجی را دریافت و نهایتا به کلاینت بفرستند.

برای طراحی یک اپلیکیشن سرور به زبان PHP، فایل های مربوط به کد های PHP را باید یک دایرکتوری در سرور قرار بگیرند. PHP و یک وب‌سرور مانند NGINX و ابزار های مورد نیاز اپلیکیشن نیز باید بر روی سرور نصب شوند.

server {
    listen 80;

    root /var/www/example;
    index index.html index.php;

    server_name example.com;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass 127.0.0.1:9000;
    }
}

کانفیگ NGINX بالا example.com:80 را ارائه می‌دهد. این کانفیگ مشابه کانفیگ مربوط به وب‌سایت های استاتیک می‌باشد و عینا همان قابلیت ها را به علاوه قابلیت های مربوط به PHP را ارائه می‌دهد. بخش هایی که برای اپلیکیشن PHP به اضافه شده است،‌ یکی جستجوی index.php در کنار index.html به هنگامی که Path درخواست متعلق به یک دایرکتوی است و دیگری پردازش فایل هایی است که پسوند php دارند.

در خواست های کلاینت در صورتی که منتهی به فایل های غیر php شوند همانند وب‌سایت های استاتیک، NGINX محتوای فایل مورد نظر را بعنوان پاسخ HTTP برمی‌گرداند. در صورتی که فایل مورد نظر، فایلی با پسوند php باشد، NGINX آدرس فایل را به PHP-FPM نصب شده رو همان سرور (به سوکت 127.0.0.1:9000) میفرستد تا PHP آنرا کامپایل کند و خروجی کد را به NGINX برگرداند. NGINX خروجی PHP را بعنوان پاسخ HTTP به کلاینت برمی‌گرداند.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/PHP

ارتباط بین اپلیکیشن های سرور

گاهی یک اپلیکیشن سرور جهت ارائه سرویس، به یک اپلیکیشن سرور دیگر (در همان سرور یا یک سرور خارجی) نیازمند است. برای مثال یک اپلیکیشن به وضعیت آب و هوای یک شهر در یک زمان خاص نیاز دارند، در این صورت باید از وب‌سرویس های آب و هوا (اپلیکیشن سرور خارجی) استفاده کند.

هنگامی که دو اپلیکیشن سمت سرور با هم ارتباط برقرار می‌کنند، می‌توان مجددا از اصطلاح اپلیکیشن کلاینت برای درخواست کننده و اپلیکیشن سرور برای سرویس دهنده استفاده می‌شود.

برای ارتباط بین اپلیکیشن های سرور می‌توان همانند ارتباط بین اپلیکیشن های کلاینت و سرور از API های RESTful استفاده کرد. از دیگر روش های ارتباط می‌توان به پروتکل های Remote Procedure Call (RPC) همانند SOAP یا gRPC که خود بر پایه پروتکل HTTP هستند یا Message Queue ها استفاده کرد.

پروتکل SOAP یک پروتکل بر پایه پروتکل ‌HTTP است که برای ارتباط میان دو اپلیکیشن استفاده می‌شود. در این پروتکل از فرمت XML برای انتقال اطلاعات استفاده می‌شود. در زبان های مختلف ماژول های کلاینت و سرور برای آن پیاده سازی شده است. با استفاده از ماژول سرور در اپلیکیشن سرور، می‌توان توابعی را پیاده ‌سازی کرد و با استفاده از ماژول کلاینت در اپلیکیشن کلاینت می‌توان آن توابع را فراخوانی کند. در پروتکل SOAP تلاش گردیده تا اپلیکیشن کلاینت بتواند توابع موجود در اپلیکیشن سرور را به آسانی توابع داخلی خود فراخوانی کند. با این حال، پروتکل SOAP امروزه محبوبیت خود را از دست داده است.

پروتکل gRPC نیز بر پایه HTTP (نسخه ۲ و بالاتر) و برای ارتباط بین دو اپلیکیشن طراحی شده است. در این پروتکل برای انتقال اطلاعات از فرمت ProtoBuf استفاده می‌شود. همانند SOAP، در این پروتکل تلاش گردیده تا اپلیکیشن کلاینت بتواند توابع موجود در اپلیکیشن سرور را به آسانی توابع داخلی خود فراخوانی کند.

در ارتباط از طریق Message Queue ها از پارادایم Publisher و Subscriber استفاده می‌شود که با روش Request/Response (درخواست و پاسخ) متفاوت است. در این نوع ارتباط، اپلیکیشنی که نقش Publisher را دارد، اطلاعات مربوط به رویدادی که رخ داده شده را منتشر می‌کند، این رویداد در صف (ابزاری مانند Redis Kafka ،NATS ،RabbitMQ و ...) قرار می‌گیرد. از طرف دیگر، اپلیکیشنی که نقش Subscriber را دارد همیشه در حال گوش دادن به صف است تا به محض اینکه رویداد جدیدی رخ داد، اطلاعات آنرا دریافت کند. برای مثال در یک سیستم، یک اپلیکیشن (A) مسئول نام‌نویسی کاربران است و یک اپلیکیشن (B) مسئول فرستادن SMS است. وقتی کاربر جدید نام‌نویسی کند، اپلیکیشن A، اطلاعاتی مانند متن پیام خوشامدگویی و شماره کاربر را در صف منتشر می‌کند. از طرف دیگر، اپلیکیشن B که Subscriber صف می‌باشد، از رویداد جدید باخبر می‌شود و اطلاعات آن را دریافت می‌کند و فرایند ارسال SMS را انجام می‌دهد.

بیشتر بخوانید:
https://en.wikipedia.org/wiki/SOAP
https://grpc.io
https://en.wikipedia.org/wiki/Message_queue

سخن پایانی

هدف از این مقاله، آشنایی علاقه‌مندان با نحوه اجرای فرایند ها در سرویس های تحت وب (وب سایت ها، وب اپلیکیشن ها، سرویس های کلاینت سرور و ...) به زبانی ساده بود. این مقاله به دلیل پوشش دادن حجم زیادی از مطالب متنوع بسیار خلاصه نوشته شده اما ممکن است در آینده کامل تر شود. در این راستا دیدگاه ها و ایده های شما کمک بزرگی خواهد بود...