در این مقاله قصد داریم شما را با ساختن یک وب سرور ابتدایی و ساده با نود جی اس آشنا کنیم. همه ی مراحل را قدم به قدم با هم انجام خواهیم داد و با نحوه ی کار هر بخش آشنا خواهیم شد . پس بیایید شروع کنیم.
نصب NodeJs و NPM و VS Code
نود جی اس یا به صورت خلاصه تر نود، یک محیط اجرایی یا runtime environment برای اجرای کد های جاوا اسکریپت ، خارج از محیط مرورگر ها می باشد. نود به صورت کاملا متن باز یا open source توسعه داده شده است و قابلیت cross platform بودن آن این امکان را در اختیار توسعه دهندگان می گذارد، که نود را روی پلتفرم های ویندوز، لینوکس و مک داشته باشند و برنامه های نوشته شده به وسیله ی نود ، در همه ی این پلتفرم ها قابل اجرا باشند. از نود اغلب برای توسعه سرویس های در بستر وب یا Api (Application Programming Interface) های تحت وب استفاده می شود. در این مقاله می خواهیم از نود برای ساختن یک وب سرور کمک بگیریم.
برای این که نود را روی سیستم تان داشته باشید، باید ابتدا آن را از سایت nodejs.org دانلود کنید. بر روی این سایت دو نسخه از نود وجود دارد. نسخه جاری یا current version و نسخه ای با پشتیبانی طولانی مدت یا LTS (Long Time Support) . توصیه می شود که نسخه ی LTS را نصب کنید چون ویژگی های اضافه شده به این نسخه همگی تست شده اند و به نقطه Stable ی رسیده اند و در دراز مدت هم حذف نخواهند شد و هم چنین امکان وجود باگ در آن ها کمتر است ولی در نسخه current ، ممکن است ویژگی هایی وجود داشته باشد که در نسخه بعدی حذف شوند و یا تغییر کنند و هم چنین امکان وجود باگ در آن ها بیشتر است. در زمان نگارش این مقاله نسخه LTS ، 16.13.2 است. پس از دانلود کردن باید آن را نصب کنید که نصب آن نکته ی خاصی ندارد و به راحتی نصب خواهد شد.
توسعه دهندگان ، برنامه هایی که با نود می نویسند را در مفهومی به نام package یا بسته قرار می دهند و آن ها را در یک repository یا مخزن مشخصی قرار می دهند تا دیگران بتوانند از آن استفاده کنند. با نصب نود یک ابزار خط فرمان به نام npm ( Node Package Manager) نصب می شود که توسط آن می توانیم این بسته ها را مدیریت کنیم ، به این معنی که بسته هایی که توسط سایر توسعه دهندگان نوشته شده اند را دریافت کرده و نسخه های مختلف بسته ها را راحت تر مدیریت کنیم . مخزن اصلی بسته ها سایت https://www.npmjs.com است. اگر به این سایت مراجعه کنید با انبوهی از بسته ها مواجه می شوید و در آن جا می توانید اطلاعاتی در مورد هر یک از آن ها جمع آوری کنید.
برای نوشتن و ویرایش کد هایمان از ویرایش گر visual studio code یا به اختصار VS Code استفاده خواهیم کرد. این ویرایش گر کاملا متن باز یا open source و رایگان است و از آن می توانید در محیط های ویندوز، لینوکس و مک از آن استفاده کنید. برای دانلود آن به سایت https://code.visualstudio.com مراجعه کنید و به بسته به سیستم عاملی که استفاده می کنید، نسخه مناسب را دانلود کرده و نصب کنید. البته شما در انتخاب ویرایش گر کد آزاد هستید و می توانید از هر ویرایش گر کد دیگری استفاده کنید چون این مورد تاثیری بر کار ما نخواهد داشت.
آماده سازی برنامه
ابتدا در مسیری خاص یک پوشه به نام firstWebServer بسازید. همه ی فایل های وب سرور مان را در این پوشه قرار می دهیم. command prompt یا خط فرمان را باز کنید و به این مسیر بروید. اگر این پوشه را در درایو d ساخته باشد خط فرمان باید به این شکل باشد:
D : \ firstWebServer >
قبل از اضافه کردن هر فایلی باید فایل package.json را به پروژه اضافه کنیم. هر پروژه ی استانداردی که با نود توسعه داده می شود حتما این فایل را شامل می شود. فایل package.json همان طور که از اسم آن پیداست یک فایل در قالب json است که شامل اطلاعاتی در مورد پروژه می باشد. اطلاعاتی شامل نام پروژه، نسخه پروژه، نویسنده پروژه، آدرس گیتهاب پروژه، وابستگی های پروژه و . . . .
برای ساخت فایل package.json از ابزار npm کمک می گیریم و دستور npm init را وارد می کنیم. npm سوال هایی در مورد اطلاعاتی که در بالا گفته شد از ما می پرسد. شما می توانید یا مقادیر پیش فرض را قبول کنید یا مقدار آن را وارد کنید. اگر می خواهید به صورت پیش فرض بدون این که سوالی پرسیده شود این فایل ساخته شود دستور را به شکل npm init –y وارد کنید تا با جواب های پیش فرض این فایل را تولید کند.
سپس در مسیری که هستیم دستور .Code را اجرا می کنیم. (با نصب VS Code می توانید این دستور را در همه جا وارد کنید) با این دستور، برنامه VS Code اجرا شده و مسیر جاری به عنوان پوشه جاری در آن باز خواهد شد. در این مسیر یک فایل جدید به نام app.js ( یا با هر نام دیگری ) می سازیم تا کد های اصلی برنامه را در آن بنویسیم.
ساختن وب سرور
پس از آماده سازی برنامه ، شروع به کد نویسی می کنیم. اولین کاری که باید انجام بدهیم این است که یک سرور ایجاد کنیم و به آن بگوییم که روی پورت خاصی شروع به گوش کردن ( listening ) بکند و درخواست ها را از این پورت دریافت کند. برای ایجاد سرور ، یکی از ماژول های خود نود را به کار خواهیم گرفت. نود به صورت پیش فرض یک سری ماژول های آماده درون خود دارد. یکی از آن ها http نام دارد. ماژول http برای ساخت برنامه های شبکه ای مانند http server ی که روی پورت خاصی درخواست ها را دریافت می کند ، کاربرد دارد.
در نود برای استفاده از یک کتابخانه یا ماژول از تابع require کمک می گیریم تا آن را وارد برنامه کنیم و از آن استفاده کنیم. این تابع یک ورودی دارد که اسم یا مسیر ماژولی که می خواهیم load کنیم را به آن می دهیم. اگر بخواهیم یکی از ماژول های خود نود را load کنیم ، اسم آن را به این تابع خواهیم داد.
برای load ماژول http باید دستور زیر را در فایل app.js وارد کنیم:
const http = require('http') ;
در مرحله بعد تعیین می کنیم که سرورمان روی چه پورتی شروع به گوش کردن خواهد کرد. این کار را با تعریف یک ثابت عددی به نام port انجام می دهیم و مقدار آن را 5000 می گذاریم. توجه کنید چون قرار نیست این مقادیر تغییر کنند از const استفاده کرده ایم.
const port = 5000 ;
در ادامه می خواهیم با کمک ماژول http، وب سرور را بسازیم. برای این کار متد createServer را روی شی http فراخوانی می کنیم. این متد یک ورودی می گیرد . ورودی این تابع خود یک تابع دیگر است که به عنوان callback عمل خواهد کرد. وقتی وب سرور درخواستی را روی پورتی که به آن داده ایم دریافت می کند، یک Event یا رخداد تولید می کند. در جواب این رخداد باید عملی انجام گیرد. عملی که در جواب رخداد رسیدن درخواست باید انجام گیرد به عنوان تابع callback به متد createServer پاس داده خواهد شد. پس کد زیر را خواهیم نوشت:
const server = http.createServer (function(req , res) {
. . .
} ) ;
تابع callback پاس داده شده دارای دو ورودی خواهد بود. پارامتر req شامل اطلاعات درخواست می باشد و در پارامتر res اطلاعات پاسخ قرار خواهد گرفت. بدنه این متد را در بخش بعد خواهیم نوشت.
بعد از ساختن شی سرور، آن را به گونه ای تنظیم می کنیم که روی پورت 5000 شروع به گوش کردن بکند. برای این کار متد listen را روی شی server فراخوانی می کنیم. این متد دو ورودی دریافت می کند. ورودی اول شماره پورتی است که باید روی آن پورت درخواست ها را دریافت کند و ورودی دوم تابع callback ی است که بعد از شروع به کار کردن متد listen فراخوانی می شود. این تابع callback یک ورودی error دارد. در صورتی که تابع listen بتواند روی پورتی که به آن داده شده است شروع به گوش کردن بکند، ورودی error با خطایی که مواجه شده است پر می شود و در غیر این صورت error با مقدار undefined باقی خواهد ماند که نشان از موفقیت آمیز بودن تابع listen خواهد بود. پس خواهیم نوشت:
server.listen (port, function (error) {
console.log (error);
if (error) {
throw new Error (error.message) ;
}
else {
console.log (' listening on port ' + port);
}
})
اگر دقت کنید مقدار error را با دستور if بررسی کرده ایم. چون مقدار undefined یک مقدار falsy است در صورت عدم رخدادن خطا ، پیام موفقیت آمیز بودن عملیات چاپ می شود و در غیر این صورت یک خطا پرتاب خواهد شد.
برای این که تا این جای کارمان را تست کنیم، در command prompt یا خط فرمان، دستور node app.js را وارد می کنیم. اگر پورت 5000 آزاد باشد و خطایی رخ ندهد پیام listening on port 5000 نمایش داده می شود و گرنه پیام خطا نمایش داده می شود.
برای متوقف کردن برنامه دکمه های Ctrl + C را فشار دهید تا به ادامه کد نویسی بپردازیم. کد های نوشته تا این مرحله به صورت زیر خواهد بود:
const http = require('http') ;
const port = 5000 ;
const server = http.createServer (function(req , res) {
} ) ;
server.listen (port, function (error) {
console.log (error);
if (error) {
throw new Error (error.message) ;
}
else {
console.log (' listening on port ' + port);
}
})
پاسخ دادن به درخواست های رسیده به وب سرور
در قدم اول می خواهیم، فارغ از این که چه درخواستی به سرور رسیده است، پیام hello world را به کاربر نشان دهیم. پس کد زیر را خواهیم نوشت:
const server = http.createServer (function (req , res) {
res.write (' Hello world ');
res.end () ;
}) ;
همان طور که می بینید، برای این که چیزی را برای کاربر ارسال کنیم از پارامتر res که نماینده response یا پاسخ درخواست می باشد، استفاده می کنیم و با متد write آن، متن hello world را برای کاربر ارسال می کنیم. برای این که تعیین کنیم کار ارسال پاسخ به پایان رسیده است، متد end را فراخوانی می کنیم. برای تست آن مجدد وب سرور را با دستور node app.js بالا آورده و سپس مرورگر را اجرا کنید و با رفتن به آدرس localhost:5000 متن hello world را خواهید دید.
در مرحله بعد می خواهیم در جواب درخواست کاربر ، به جای متن ، یک صفحه ی HTML را در وب سرور تولید کرده و آن را برای کاربر ارسال کنیم تا محتوای آن را در مرورگر مشاهده کند. در قدم اول باید صفحه ی HTML ی که می خواهیم برای کاربر ارسال شود را به پروژه اضافه کنیم پس یک فایل به نام index.html را به پروژه اضافه می کنیم و آن را با کد های زیر پر می کنیم.
<!DOCTYPE html>
<html lang="en">
<head>
<title> First Web Server with Node </title>
</head>
<body>
<p> This is first web server with node </p>
</body>
</html>
به فایل app.js بر می گردیم و در تابع callback متد createServer، که هر بار با رسیدن هر درخواستی به وب سرور فراخوانی می شود ، برای این که صفحه ی HTML برای کاربر ارسال شود، تغییرات را اعمال می کنیم . وقتی مرورگر درخواستی را به وب سرور می فرستد و وب سرور در جواب آن متنی را برای مرورگر می فرستد، باید به مرورگر اعلام کند که متن ارسالی یک فایل html می باشد تا مرورگر با آن به عنوان یک صفحه ی HTML بر خورد کند و آن را به درستی نمایش دهد. برای این کار در بخش header پاسخ ارسالی داده هایی را باید اضافه کنیم. پس خط زیر را به تابع callback اضافه می کنیم:
res.writeHead (200 , { 'Content-Type' : 'text/html' } ) ;
برای نوشتن روی بخش header پاسخ از متد writeHead شی res کمک می گیریم . اولین پارامتر این متد کد وضعیت یا status code پاسخ می باشد . در پروتکل http هر پاسخی دارای کدی است که درخواست دهنده از روی آن متوجه می شود که پاسخ دریافت شده در چه وضعیتی است. کد 200 به این معنی است که عملیات درخواست و پاسخ به درستی انجام شده است . دومین پارامتر متد writeHead ، json ی است که شامل header هایی است که به پاسخ اضافه می شوند. در این json، هدر ها به صورت کلید و مقدار اضافه می شوند. مثلا برای این که تعیین کنیم نوع محتوای پاسخ از نوع html است، باید هدر Content-Type را با مقدار text/html به پاسخ اضافه کنیم .
کار بعدی که باید انجام بدهیم این است که فایل index.html را بخوانیم تا محتویات آن را در پاسخ درخواست قرار داده و برای کاربر ارسال کنیم . برای خواندن از فایل ، از یکی دیگر از ماژول های آماده ی نود به نام file system یا fs استفاده می کنیم . این ماژول دارای متد هایی است برای کار روی فایل ها و پوشه ها . از تابع require کمک می گیریم تا این ماژول را وارد برنامه کرده و از متد های آن استفاده کنیم .
const fs = require ('fs') ;
از متد readFile ماژول fs استفاده می کنیم تا محتویات فایل index.html را بخوانیم. این متد دو پارامتر دارد. پارامتر اول فایلی است که باید خوانده شود و پارامتر دوم یک تابع callback است که بعد از خواندن فایل فراخوانی می شود. تابع callback دو پارامتر خواهد داشت . پارامتر اول موفقیت آمیز بودن یا نبودن عملیات را نشان می دهد و پارامتر دوم محتویات فایل خوانده شده نگه می دارد . پس قطعه کد زیر را می نویسیم:
fs.readFile ('index.html' , function (err , data) {
if (err) {
res.writeHead (404) ;
res.write (' Error : File not found ') ;
} else {
res.write (data) ;
}
res.end() ;
})
ابتدا مقدار پارامتر err بررسی می شود که آیا با خطا مواجه شدیم یا نه. اگر خطا داشتیم، status code یا کد وضعیت را با 404 مقدار دهی می کنیم. کد 404 به این معنی است که کاربر درخواست فایلی را داده که آن فایل در سرور وجود ندارد. همراه کد 404 متن Error : File not found را برای کاربر ارسال می کنیم تا در مرورگر مشاهده کند.
در صورتی که خطایی رخ ندهد متن فایل خوانده شده در پارامتر data قرار می گیرد پس مقدار آن را برای کاربر می فرستیم و در آخر با فراخوانی متد end پایان پاسخ را اعلام می کنیم.
برای تست تغییرات انجام شده ابتدا با Ctrl + C سرور را متوقف کرده و با دستور node app.js سرور را مجدد اجرا کنید. به آدرس localhost:5000 بروید و باید تصویر زیر را مشاهده کنید:
اضافه کردن قابلیت مسیردهی به در خواست ها
تا اینجای کار هر درخواستی که به دست وب سرور برسد، وب سرور یک پاسخ را تولید کرده و آن را تحویل درخواست دهنده می دهد. اگر نیاز باشد بنا بر نوع درخواست کاربر، وب سرور پاسخ خاصی را تولید کند نیاز خواهیم داشت که در وب سرور درخواست ها را مسیردهی کنیم.
همان طور که قبلا اشاره شده اطلاعات درخواست درون پارامتر req قرار می گیرد . از این پارامتر می توان آدرس url ی که درخواست شده است را خواند . اگر درخواست به صورت /localhost:5000 باشد یعنی هیچ گونه path ی در url تعیین نشده باشد می خواهیم پیام hello world به کاربر بر گردد و اگر درخواست رسیده به صورت localhost:5000/index.html باشد ، صفحه ی index.html برای کاربر فرستاده شود. پس تغییرات زیر را در کد اعمال می کنیم:
const server = http.createServer(function (req, res) {
if (req.url === '/') {
. . .
}
if (req.url === '/index.html') {
. . .
}
});
همان طور که می بینید مقدار url را از پارامتر req می خوانیم و براساس مقدار این پارامتر، آن چه که باید برای کاربر فرستاده شود را مسیر دهی می کنیم. به این کار routing یا مسیر دهی گفته می شود. برای تست آن مجدد وب سرور را متوقف کرده و دوباره اجرا کنید. آدرس هایی که در بالا گفته شد را وارد کنید تا مسیر دهی درخواست ها را ببینید.
در آخر متن کامل کد هایی که نوشتیم را می توانید در زیر ببینید:
const http = require('http') ;
const fs = require('fs') ;
const port = 5000 ;
const server = http.createServer(function (req, res) {
if (req.url === '/') {
res.write(' Hello world ') ;
res.end() ;
}
if (req.url === '/index.html') {
res.writeHead (200, { 'Content-Type': 'text/html' });
fs.readFile('index.html', function (err, data) {
if (err) {
res.writeHead(404);
res.write(' Error : File not found ') ;
} else {
res.write (data) ;
}
res.end();
})
}
});
server.listen (port , function (error) {
console.log (error);
if (error) {
throw new Error(error.message) ;
}
else {
console.log(' listening on port ' + port);
}
})
همان طور که دیدید ساختن وب سرور با نود بسیار کار ساده ای می باشد اما در پروژه های بزرگ از ماژول http برای ساختن وب سرور و سرویس های تحت وب استفاده نمی کنند. یکی از دلایل آن این است که چون مجبوریم مسیر دهی های فراوانی را دستی در تابع callback وارد کنیم، برنامه پیچیده خواهد شد. به جای آن از فریم ورک محبوب express استفاده می کنند. در مقاله های بعد استفاده از این فریم ورک را شرح خواهیم داد.