امروزه تعامل بین برنامههای وب بر انواع درخواست HTTP متکی است. به عنوان مثال، فرض کنید یک برنامه فروشگاه آنلاین داریم و میخواهیم یک محصول جدید در آن ایجاد کنیم. برای این منظور، ما باید تمام اطلاعات لازم را پر کنیم و احتمالاً روی دکمهای تحت عنوان «ایجاد محصول» کلیک نماییم.
این عمل یک درخواست HTTP را به همراه تمام دادههای لازم به بکاند ارسال میکند و برنامه ما از آن دادهها برای ایجاد تغییرات در پایگاه داده استفاده مینماید. پس از اتمام عملیات، که میتواند موفقیتآمیز باشد یا نه، یک پاسخ HTTP به فرانتاند ارسال میشود که بر اساس وضعیت آن پاسخ، مطابق با آن عمل میکند.
هنگامی که این درخواستها و پاسخها بین بکاند و فرانتاند منتقل میشوند، باید از قالب خاصی پیروی داشته باشند تا هر دو طرف بتوانند منظور یکدیگر را درک کنند. HTTP برای این منظور ایجاد شده است و یک پروتکل شبکه استاندارد میباشد که برنامههای تحت وب را قادر میسازد تا یکدیگر را درک کرده و با همدیگر ارتباط برقرار نمایند.
چندین متد وجود دارد که میتوانیم برای ارسال درخواست HTTP از آنها استفاده کنیم و هر کدام از آنها وظایف متفاوتی را انجام میدهند، همانطور که در ادامه داریم:
متد GET برای درخواست دادهها و منابع از سرور استفاده میشود. هنگامی که یک درخواست GET ارسال میکنیم، پارامترهای کوئری در URL به صورت جفتهای name/value به شکل زیر تعبیه میشوند:
http://example.com/index.html?name1=value1&name2=value2
باید به این نکته توجه داشته باشیم که علامت ? نشان دهنده آغاز لیستی از پارامترها است. هر پارامتر یک جفت name/value (name=value) را تشکیل میدهد و علامت & برای تقسیم دو پارامتر مختلف استفاده میشود.
متد POST برای ارسال دادهها به سرور، یا افزودن یک منبع جدید یا بهروزرسانی یک منبع موجود مورد استفاده قرار میگیرد. پارامترها در بدنه درخواست HTTP ذخیره میشوند.
POST /index.html HTTP/1.1 Host: example.com name1=value1&name2=value2
این متد یک منبع را از سرور حذف میکند.
متد HEAD دقیقاً مانند متد GET عمل میکند با این تفاوت که پاسخ HTTP ارسال شده از سرور فقط شامل head است اما body را شامل نمیشود. این به این معنی است که اگر سرور با درخواست “OK” باشد، به ما پاسخ 200 OK را میدهد اما منبعی را که درخواست کرده بودیم نمیدهد. ما فقط میتوانیم منبع را با متد GET بازیابی کنیم.
این متد زمانی که در حال تست کارکرد سرور هستیم بسیار مفید میباشد. گاهی اوقات، انتقال منبع ممکن است زمان زیادی طول بکشد، اما برای اهداف آزمایشی فقط به یک پاسخ 200 OK نیاز داریم تا بدانیم همه چیز به درستی کار میکند یا نه.
متد PUT برای بهروزرسانی منابع موجود استفاده میشود و با یک تفاوت کوچک بسیار شبیه به متد POST است. وقتی منبعی را که از قبل وجود دارد PUT کنیم، منبع قدیمی بازنویسی میشود؛ و ایجاد چندین درخواست PUT یکسان، همان اثری را خواهد داشت که یک بار آن را انجام دهیم.
وقتی منابع یکسانی را POST میکنیم، هر بار که درخواست ارسال میگردد، آن منبع کپی میشود.
برای مدت زمان طولانی، جامعه جاوااسکریپت فاقد یک روش استاندارد برای ارسال درخواستهای HTTP بود. برخی از افراد از XMLHttpRequest با نام مستعار AJAX استفاده میکردند، در حالی که برخی دیگر استفاده از کتابخانههای خارجی مانند Axios یا jQuery را ترجیح میدادند.
Fetch API در سال 2015 به عنوان روشی مدرن، ساده و استاندارد برای ایجاد درخواستهای HTTP با استفاده از جاوااسکریپت معرفی شد که به صورت native پشتیبانی میشود. بنابراین نیازی به نصب کتابخانههای third-party وجود ندارد.
Fetch API مبتنی بر promise است، به این معنی که یک سینتکس تمیز و مختصر برای نوشتن عملیات asynchronous ارائه میدهد. به عنوان مثال، به این صورت است که میتوانیم یک درخواست GET با استفاده از fetch API ارسال نماییم.
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => {
// If the response is not 2xx, throw an error
if (!response.ok) {
throw new Error("Network response was not ok");
}
// If the response is 200 OK, return the response in JSON format.
return response.json();
})
.then((data) => console.log(data)) // You can continue to do something to the response.
.catch((error) => console.error("Fetch error:", error)); // In case of an error, it will be captured and logged.
همچنین میتوانیم گزینههای سفارشی مانند headers سفارشی، توکنهای authorization و غیره را به درخواست اضافه کنیم.
fetch("https://jsonplaceholder.typicode.com/users", {
headers: {
"Content-Type": "application/json",
"Authorization": "your-token-here",
},
credentials: "same-origin",
})
.then(. . .);
هنگام ارسال درخواست POST، همه چیز کمی پیچیدهتر میشود زیرا، باید دادهها را با request body به سرور ارسال نماییم. این موضوع ممکن است بسته به نوع دادهای که ارسال میکنیم و مورد استفاده خاص ما پیچیده شود.
به عنوان مثال، کد زیر دادههای JSON را به بکاند ارسال میکند:
fetch("https://jsonplaceholder.typicode.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "John Doe",
email: "johndoe@example.com",
}),
});
در اینجا باید به چند نکته توجه کنیم. اول از همه، ما باید به صراحت method درخواست را مشخص کنیم. اگر این را انجام ندهیم، به طور پیشفرض از متد GET استفاده میشود.
همچنین request body فقط دادههای string را میپذیرد، بنابراین باید قبل از اختصاص دادن هر مقداری به request body از متد stringify() برای تبدیل JSON به string استفاده کنیم.
علاوه بر این، مهم است که حتما header Content-Type را درج کنیم تا دریافت کننده بداند که چگونه باید request body را تجزیه کند.
با این حال، مسائل معمولاً در عمل پیچیدهتر هستند. به عنوان مثال، هنگام کار با وب فرمها، به جای JSON، احتمالاً از encoding فرم x-www-form-urlencoded استفاده میکنیم، در این صورت درخواست میتواند به این صورت ارسال شود. به عنوان مثال:
document.addEventListener("DOMContentLoaded", function () {
const form = document.querySelector("form");
const usernameInput = document.getElementById("username");
const emailInput = document.getElementById("email");
const formData = new URLSearchParams();
usernameInput.addEventListener("input", function () {
formData.set("username", usernameInput.value);
});
emailInput.addEventListener("input", function () {
formData.set("email", emailInput.value);
});
form.addEventListener("submit", async function (event) {
event.preventDefault(); // Prevent the default form submission action
await fetch("https://jsonplaceholder.typicode.com/users", {
method: "POST",
body: formData.toString(),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
});
});
اگر نیاز داریم تا فایلها را در بکاند آپلود کنیم، لازم است به جای آن از encoding فرم multipart/form-data استفاده نماییم.
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById("myForm");
const usernameInput = document.getElementById("username");
const emailInput = document.getElementById("email");
const pictureInput = document.getElementById("picture");
const formData = new FormData();
usernameInput.addEventListener("input", function () {
formData.set("username", usernameInput.value);
});
emailInput.addEventListener("input", function () {
formData.set("email", emailInput.value);
});
pictureInput.addEventListener("change", function () {
formData.set("picture", pictureInput.files[0]);
});
form.addEventListener("submit", async function (event) {
event.preventDefault(); // Prevent the default form submission
await fetch("https://jsonplaceholder.typicode.com/users", {
method: "POST",
body: formData,
});
});
});
باید به این نکته توجه داشته باشیم که هنگام استفاده از FormData() برای ساخت request body، Content-Typeدر multipart/form-data قفل میشود. در این مورد، نیازی به تنظیم header Content-Type سفارشی نداریم.
درخواست PUT مشابه POST عمل میکند، اما باید method را روی PUT تنظیم کنیم.
fetch("https://jsonplaceholder.typicode.com/users", {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
id: "123"
name: "John Doe",
email: "johndoe@example.com",
}),
});
در واقع، ما باید یک id یا هر کلید دیگری ارائه دهیم که این امکان را فراهم کند تا بتوانیم رکورد مورد نظر خود را برای بهروزرسانی در بکاند پیدا کنیم.
درخواست DELETE مشابه PUT کار میکند، اما باید به خاطر داشته باشیم که method را روی DELETE تنظیم کنیم.
fetch("https://jsonplaceholder.typicode.com/users/123", {
method: "DELETE",
});
و به طور مشابه، به یاد داشته باشیم که یک id ارائه کنیم تا برنامه بکاند بداند کدام رکورد را حذف کند.
علاوه بر fetch()، امکان ایجاد درخواست HTTP با استفاده از XMLHttpRequest نیز وجود دارد. مثال زیر نحوه ایجاد یک درخواست GET به endpoint https://jsonplaceholder.typicode.com را نشان میدهد.
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://jsonplaceholder.typicode.com/users", true);
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(JSON.parse(xhr.responseText));
} else {
console.error("Error:", xhr.statusText);
}
};
xhr.onerror = function () {
console.error("Request failed");
};
xhr.send();
سینتکس این روش کمی پیچیدهتر است، زیرا XMLHttpRequest برای کار با عملیات asynchronous به توابع callback متکی است. این بدان معناست که نتیجه به راحتی میتواند به callback hell منجر شود، که در آن ما لایه به لایه از توابع callback را داریم که خواندن و نگهداری کد را دشوار میکند.
با این حال، XMLHttpRequest مزایایی هم دارد. با توجه به این واقعیت که XMLHttpRequest در مقایسه با fetch() بسیار قدیمیتر است، از این رو، پشتیبانی گستردهای دارد. زمانی که برنامه وب ما نیاز دارد که با مرورگرهای قدیمی سازگار باشد، باید از XMLHttpRequest استفاده کنیم.
جدا از متدهای built-in، ما میتوانیم درخواستهای HTTP را با استفاده از کتابخانههای third-party نیز ارسال کنیم. به عنوان مثال، نحوه ارسال درخواست GET با استفاده از jQuery به صورت زیر میباشد:
$.get("https://api.example.com/data", function (data) {
console.log(data);
}).fail(function (error) {
console.error("Error:", error);
});
jQuery یکی از محبوبترین کتابخانههای جاوااسکریپت است. هدف آن رفع بخشی از جاوااسکریپت است که استفاده از آن دشوار میباشد و در این زمینه بسیار موفق بوده است.
در سالهای اخیر، jQuery محبوبیت خود را از دست داده است زیرا vanilla جاوااسکریپت در طول سالها بهبود پیدا کرده و مشکلاتی که قبلاً افراد را آزار میداد اکنون برطرف شده است. بنابراین، این کتابخانه دیگر گزینه اصلی برای ایجاد برنامههای جاوااسکریپت نیست.
از طرف دیگر، میتوانیم با Axios کار کنیم، که یک کلاینت HTTP مبتنی بر promise است و مانند fetch() عمل میکند، و برای مدت طولانی قبل از آمدن fetch() مورد توجه توسعهدهندگان قرار گرفته بود.
axios
.get("https://api.example.com/data")
.then((response) => console.log(response.data))
.catch((error) => console.error("Axios error:", error));
Axios و fetch() سینتکس بسیار مشابهی دارند زیرا هر دو مبتنی بر promise هستند. تفاوت اصلی بین آنها این است که fetch() یک متد داخلی است، در حالی که Axios از ما میخواهد که یک کتابخانه خارجی نصب کنیم.
با این حال، Axios از ویژگیهای بسیار غنیتری برخوردار است، زیرا با رهگیریهای درخواست و پاسخ، مدیریت خودکار JSON و زمانبندی داخلی همراه میباشد.
ما در این مقاله چهار راه مختلف برای ارسال انواع درخواست HTTP با استفاده از جاوااسکریپت را بررسی کردیم و بسته به پروژهای که داریم میتوانیم از هر کدام از آنها استفاده کنیم.
Fetch API روشی مدرن و استاندارد برای ایجاد درخواستهای HTTP با استفاده از جاوااسکریپت است که یک سینتکس نسبتاً ساده دارد که نگهداری پروژه ما را آسانتر میکند.
XMLHttpRequest روش قدیمی برای ارسال درخواستهای HTTP میباشد. استفاده از این روش معمولاً برای پروژههای جدید توصیه نمیشود، اما اگر پروژه ما باید با مرورگرهای قدیمی سازگار باشد، XMLHttpRequest ممکن است همچنان مفید باشد.
jQuery یک پکیج خارجی است که میتواند کارهای زیادی از جمله ارسال درخواستهای HTTP را انجام دهد. اگرچه اهمیت jQuery در سالهای اخیر کمرنگ شده است، اما هنوز در بسیاری از پروژههای قدیمی مورد استفاده قرار میگیرد و ممکن است در کار خود به عنوان یک توسعهدهنده جاوااسکریپت با آن مواجه شویم.
Axios یک کتابخانه third-party است که برای ارسال درخواستهای HTTP استفاده میشود. این کتابخانه سینتکس بسیار شبیه به fetch API دارد اما دارای ویژگیهای بسیار پیشرفتهتری میباشد. این ما هستیم که باید تصمیم بگیریم که آیا در پروژه خود به این ویژگیها نیاز داریم یا خیر. اگر نه، به طور کلی توصیه میشود به جای آن از fetch() استفاده کنیم.