کار با URL در جاوااسکریپت

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

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

آشنایی با بخش‌های مختلف یک URL

آدرس URL زیر را در نظر می‌گیریم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
https://example.com/api/search?query=foo&sort=asc#results
https://example.com/api/search?query=foo&sort=asc#results
https://example.com/api/search?query=foo&sort=asc#results

این آدرس URL شامل بخش‌های زیر است:

  • پروتکل:
    https
    https
  • هاست:
    example.com
    example.com
  • مسیر:
    /api/search
    /api/search
  • query string:
    ?query=foo&sort=asc
    ?query=foo&sort=asc
  • هش:
    #results
    #results

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

تجزیه URL‌ها

در مرورگرهای قدیمی، قبل از اینکه API 

URL
URL معرفی شود، یکی از روش‌های معمول برای تجزیه آدرس‌های URL استفاده از المنت
<a>
<a> بود. این المنت قابلیت‌هایی برای تجزیه ابتدایی URL ارائه می‌داد. به عنوان مثال، می‌توانستیم query string را از یک URL استخراج کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function getQueryString(url) {
const link = document.createElement('a');
link.href = url;
return url.search;
}
function getQueryString(url) { const link = document.createElement('a'); link.href = url; return url.search; }
function getQueryString(url) {
  const link = document.createElement('a');
  link.href = url;
  return url.search;
}

این روش، با وجود سادگی، محدودیت‌هایی داشت:

  1. نیازمند یک محیط DOM بود، به این معنا که در محیط‌هایی مثل Node.js کار نمی‌کرد.
  2. هیچ مکانیزم مدیریت خطایی نداشت؛ اگر یک URL نامعتبر به ویژگی
    href
    href داده می‌شد، خطایی رخ نمی‌داد.

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

استفاده از API 

URL
URL برای تجزیه URL‌ها بسیار ساده است. تنها کافی است آدرس URL مورد نظر را به
URL
URL constructor ارسال کنیم. اگر رشته URL معتبر باشد، یک آبجکت
URL
URL به ما return می‌شود که شامل ویژگی‌هایی برای دسترسی به بخش‌های مختلف URL است.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const url = new URL('https://example.com/api/search?query=foobar');
console.log(url.host); // example.com
console.log(url.pathname); // /api/search
console.log(url.search); // ?query=foobar
const url = new URL('https://example.com/api/search?query=foobar'); console.log(url.host); // example.com console.log(url.pathname); // /api/search console.log(url.search); // ?query=foobar
const url = new URL('https://example.com/api/search?query=foobar');
console.log(url.host); // example.com
console.log(url.pathname); // /api/search
console.log(url.search); // ?query=foobar

تجزیه Query String

می‌توانیم query string یک

URL
URL را به دو روش استخراج کنیم:

  1. ویژگی
    search
    search: این ویژگی، یک رشته است که شامل کل query string می‌شود (همراه با کاراکتر
    ?
    ?).
  2. ویژگی
    searchParams
    searchParams: این ویژگی، یک آبجکت از نوع
    URLSearchParams
    URLSearchParams است.

اگر بخواهیم مقدار یک پارامتر خاص در query string را بدانیم، می‌توانیم از متد

get
get استفاده کنیم تا مقدار آن پارامتر را با نامش دریافت نماییم.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const url = new URL('https://example.com/api/search?query=foobar&maxResults=10');
console.log(url.searchParams.get('query'); // foobar
console.log(url.searchParams.get('maxResults'); // 10
const url = new URL('https://example.com/api/search?query=foobar&maxResults=10'); console.log(url.searchParams.get('query'); // foobar console.log(url.searchParams.get('maxResults'); // 10
const url = new URL('https://example.com/api/search?query=foobar&maxResults=10');
console.log(url.searchParams.get('query'); // foobar
console.log(url.searchParams.get('maxResults'); // 10

اگر چندین پارامتر با نام یکسان وجود داشته باشد، می‌توانیم از متد

getAll
getAll استفاده کنیم تا آرایه‌ای شامل تمامی مقادیر آن نام را دریافت نماییم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const url = new URL('https://example.com/api/search?tag=tag1&tag=tag2&tag=tag3');
console.log(url.searchParams.getAll('tag')); // ['tag1', 'tag2', 'tag3']
const url = new URL('https://example.com/api/search?tag=tag1&tag=tag2&tag=tag3'); console.log(url.searchParams.getAll('tag')); // ['tag1', 'tag2', 'tag3']
const url = new URL('https://example.com/api/search?tag=tag1&tag=tag2&tag=tag3');
console.log(url.searchParams.getAll('tag')); // ['tag1', 'tag2', 'tag3']

ساخت Query String

ساختن query string به صورت دستی می‌تواند مشکل باشد، مخصوصاً اگر پارامترها شامل کاراکترهای خاصی باشند که نیاز به کدگذاری دارند. به‌عنوان مثال، اگر یک پارامتر نیاز داشته باشد که شامل کاراکتر

&
& باشد، باید آن را به عنوان
%۲۶
%۲۶ کدگذاری کنیم. برای مدیریت این موارد، باید از تابع
encodeURIComponent
encodeURIComponent استفاده نماییم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let queryString = 'foo=bar';
queryString += '&baz=qux';
queryString += '&tag=' + encodeURIComponent('one&two');
console.log(queryString); // foo=bar&baz=qux&tag=one%26two
let queryString = 'foo=bar'; queryString += '&baz=qux'; queryString += '&tag=' + encodeURIComponent('one&two'); console.log(queryString); // foo=bar&baz=qux&tag=one%26two
let queryString = 'foo=bar';
queryString += '&baz=qux';
queryString += '&tag=' + encodeURIComponent('one&two');
console.log(queryString); // foo=bar&baz=qux&tag=one%26two

اما می‌توانیم با استفاده از آبجکت

URLSearchParams
URLSearchParams به صورت ایمن‌تر query string را بسازیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const params = new URLSearchParams();
params.append('foo', 'bar');
params.append('baz', 'qux');
params.append('tag', 'one&two');
console.log(params.toString()); // foo=bar&baz=qux&tag=one%26two
const params = new URLSearchParams(); params.append('foo', 'bar'); params.append('baz', 'qux'); params.append('tag', 'one&two'); console.log(params.toString()); // foo=bar&baz=qux&tag=one%26two
const params = new URLSearchParams();
params.append('foo', 'bar');
params.append('baz', 'qux');
params.append('tag', 'one&two');
console.log(params.toString()); // foo=bar&baz=qux&tag=one%26two

مزایای استفاده از  URLSearchParams

استفاده از

URLSearchParams
URLSearchParams مزایایی دارد که عبارتند از:

  • نیازی نیست نگران کاراکتر
    &
    & برای جداسازی پارامترها باشیم.
  • نیازی به کدگذاری مقادیر پارامترها به صورت دستی نیست.
  • نیازی به استفاده از الحاق رشته (String Concatenation) نداریم.

پیمایش پارامترهای جستجو

بدون استفاده از آبجکت

URLSearchParams
URLSearchParams، پیمایش پارامترهای یک query string کمی پیچیده می‌شود. در این حالت، باید چندین بار رشته را تقسیم کنیم؛ یک بار برای جدا کردن پارامترها به عنوان جفت‌های key/value و بار دیگر برای تفکیک key از value در هر پارامتر:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function listQueryParams(queryString) {
queryString.split('&').forEach(param => {
const [key, value] = param.split('=');
console.log(`${key}: ${value}`);
});
}
function listQueryParams(queryString) { queryString.split('&').forEach(param => { const [key, value] = param.split('='); console.log(`${key}: ${value}`); }); }
function listQueryParams(queryString) {
  queryString.split('&').forEach(param => {
    const [key, value] = param.split('=');
    console.log(`${key}: ${value}`);
  });
}

اگر پارامترها شامل کاراکترهای کدگذاری شده باشند، باید آن‌ها را نیز decode کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function listQueryParams(queryString) {
queryString.split('&').forEach(param => {
const [key, value] = param.split('=');
console.log(`${key}: ${decodeURIComponent(value)}`);
});
}
function listQueryParams(queryString) { queryString.split('&').forEach(param => { const [key, value] = param.split('='); console.log(`${key}: ${decodeURIComponent(value)}`); }); }
function listQueryParams(queryString) {
  queryString.split('&').forEach(param => {
    const [key, value] = param.split('=');
    console.log(`${key}: ${decodeURIComponent(value)}`);
  });
}

اما با استفاده از متد

entries
entries آبجکت
URLSearchParams
URLSearchParams می‌توانیم به سادگی روی جفت‌های key/value پیمایش کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function listQueryParams(queryString) {
const params = new URLSearchParams(queryString);
params.entries().forEach(([key, value]) => console.log(`${key}: ${value}`));
}
function listQueryParams(queryString) { const params = new URLSearchParams(queryString); params.entries().forEach(([key, value]) => console.log(`${key}: ${value}`)); }
function listQueryParams(queryString) {
  const params = new URLSearchParams(queryString);
  params.entries().forEach(([key, value]) => console.log(`${key}: ${value}`));
}

ساخت یک URL کامل

برای ساخت یک URL کامل با یک آدرس پایه و چندین پارامتر جستجو، می‌توانیم از ترکیب URL و URLSearchParams استفاده کنیم. مثال زیر یک روش کامل را نشان می‌دهد:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const url = new URL('https://example.com/api/search');
url.searchParams.append('query', 'test');
url.searchParams.append('tag', 'tag1');
url.searchParams.append('tag', 'tag2');
// https://example.com/api/search?query=test&tag=tag1&tag=tag2
console.log(url.toString());
const url = new URL('https://example.com/api/search'); url.searchParams.append('query', 'test'); url.searchParams.append('tag', 'tag1'); url.searchParams.append('tag', 'tag2'); // https://example.com/api/search?query=test&tag=tag1&tag=tag2 console.log(url.toString());
const url = new URL('https://example.com/api/search');
url.searchParams.append('query', 'test');
url.searchParams.append('tag', 'tag1');
url.searchParams.append('tag', 'tag2');

// https://example.com/api/search?query=test&tag=tag1&tag=tag2
console.log(url.toString());

بررسی معتبر بودن URLها

ممکن است بخواهیم از یک regular expression برای اعتبارسنجی یک URL استفاده کنیم، اما نوشتن یک regular expression که بتواند همه URLهای معتبر را به درستی شناسایی کند، کار بسیار دشواری است.

به جای آن، می‌توانیم از API

URL
URL استفاده کنیم. اگر یک URL نامعتبر به
URL
URL Constructor داده شود، خطا تولید می‌کند. این ویژگی برای بررسی معتبر بودن URLها مفید است:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function isValidURL(url) {
try {
new URL(url);
return true;
} catch (error) {
return false;
}
}
function isValidURL(url) { try { new URL(url); return true; } catch (error) { return false; } }
function isValidURL(url) {
  try {
    new URL(url);
    return true;
  } catch (error) {
    return false;
  }
}

مرورگرهای جدیدتر این کار را ساده‌تر کرده‌اند. متد استاتیک

URL.canParse
URL.canParse اضافه شده است که با یک خط کد، اعتبارسنجی مشابهی را انجام می‌دهد. درست مانند تابع
isValidURL
isValidURL که در بالا دیدیم، این متد در جاوااسکریپت یک رشته URL دریافت می‌کند و بسته به معتبر بودن آن، مقدار
true
true یا
false
false برمی‌گرداند.

ساخت URLهای نسبی

API

URL
URL یک مکانیزم قدرتمند برای تبدیل URLهای نسبی به کامل ارائه می‌دهد. به‌طور معمول، اگر URLای که به
URL
URL constructor داده می‌شود، کامل و معتبر نباشد، خطا ایجاد می‌کند. اما اگر یک آرگومان دوم به آن بدهیم، این آرگومان به عنوان یک URL پایه عمل می‌کند تا URL نسبی را بر اساس آن بسازد.

در این روش، یعنی روش دو آرگومانی، آرگومان اول نیازی به معتبر یا کامل بودن ندارد، اما آرگومان دوم باید یک URL معتبر و کامل باشد. به عنوان مثال:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
new URL('/about', 'https://example.com').href;
new URL('/about', 'https://example.com').href;
new URL('/about', 'https://example.com').href;

URL
URL constructor، آدرس پایه
https://example.com
https://example.com را می‌گیرد و مسیر نسبی
/about
/about را به آن اضافه می‌کند. در نتیجه، خروجی
https://example.com/about
https://example.com/about خواهد بود.

یک مثال دیگر:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
new URL('profile', 'https://example.com/users').href;
new URL('profile', 'https://example.com/users').href;
new URL('profile', 'https://example.com/users').href;

ممکن است انتظار داشته باشیم که نتیجه

https://example.com/users/profile
https://example.com/users/profile باشد، اما در واقع خروجی
https://example.com/profile
https://example.com/profile خواهد بود. این رفتار دقیقاً مانند یک لینک نسبی عمل می‌کند؛ یعنی بخش parent مسیر را که ریشه
example.com
example.com است، در نظر می‌گیرد و سپس
profile
profile را به آن اضافه می‌کند.

یک مثال دیگر از استفاده URL نسبی را بررسی می‌کنیم. می‌توانیم از

..
.. استفاده کنیم تا یک سطح به عقب در ساختار مسیر برویم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
new URL('../profile', 'https://example.com/users/123').href;
new URL('../profile', 'https://example.com/users/123').href;
new URL('../profile', 'https://example.com/users/123').href;

در این مثال URL در نهایت به

https://example.com/profile
https://example.com/profile تبدیل می‌شود. باید این موضوع را به خاطر داشته باشیم که آدرس‌های URL نسبی از بخش parent مسیر شروع می‌شوند. در اینجا،
..
.. باعث می‌شود که یک سطح بالاتر در مسیر حرکت کنیم.

اگر هنگام استفاده از

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
new URL('../profile', '/about'); // error!
new URL('../profile'); // error
new URL('../profile', '/about'); // error! new URL('../profile'); // error
new URL('../profile', '/about'); // error!
new URL('../profile'); // error

کار با آبجکت window.location

احتمالا با آبجکت

window.location
window.location در جاوااسکریپت آشنا هستیم، که نماینده URL صفحه فعلی می‌باشد. این آبجکت دارای ویژگی‌هایی مانند
href
href و
pathname
pathname است، بنابراین ممکن است فکر کنیم که یک آبجکت
URL
URL است. اما در واقع این یک آبجکت
Location
Location است که برخی ویژگی‌های مشترک با
URL
URL دارد، اما برخی ویژگی‌ها مانند
searchParams
searchParams را ندارد.

با اینکه این آبجکت یک

URL
URL کامل نیست، اما می‌توانیم از آن برای ساخت آبجکت‌های جدید
URL
URL استفاده کنیم. به عنوان مثال، می‌توانیم
window.location
window.location را به
URL
URL constructor بدهیم تا یک
URL
URL کامل با ویژگی‌هایی مثل
searchParams
searchParams بر اساس URL فعلی بسازیم، یا حتی از آن به عنوان URL پایه برای ساخت URLهای نسبی استفاده کنیم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
new URL('/profile', window.location).href;
new URL('/profile', window.location).href;
new URL('/profile', window.location).href;

مطابقت الگوها در URL با استفاده از URLPattern

استفاده از

URL
URL باعث می‌شود تا بتوانیم به سادگی path را از یک URL استخراج کنیم. به عنوان مثال، در URL 
https://example.com/api/users/123/profile
https://example.com/api/users/123/profile مقدار pathname برابر با
/api/users/123/profile
/api/users/123/profile است. اما اگر بخواهیم فقط ID کاربر (
۱۲۳
۱۲۳) را از این URL استخراج کنیم، چه کاری باید انجام بدهیم؟

همان‌طور که قبلاً به آن اشاره کردیم، ایجاد regular expressionها برای اعتبارسنجی و استخراج بخش‌های خاص از یک URL می‌تواند دشوار باشد.

API جدیدی به نام

URLPattern
URLPattern در جاوااسکریپت وجود دارد که می‌تواند برای تطبیق و استخراج بخش‌هایی از URL، بر اساس الگوهای مشخص مورد استفاده قرار بگیرد. این قابلیت به ویژه در برنامه‌هایی مثل routing سمت کلاینت در اپلیکیشن‌های تک‌صفحه‌ای (SPA) بسیار مفید است.

با استفاده از URL مربوط به پروفایل کاربر به عنوان مثال، می‌خواهیم یک

URLPattern
URLPattern ایجاد کنیم تا ID کاربر را استخراج نماییم. می‌توانیم از کاراکتر
:
: در ابتدای یک placeholder نام‌گذاری شده استفاده کنیم، که بعداً برای تطبیق آن بخش از URL به کار می‌رود:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
const pattern = new URLPattern('https://example.com/api/users/:userId/profile');
const matcher = pattern.exec('https://example.com/api/users/123/profile');
console.log(matcher.pathname.groups.userId); // 123
const pattern = new URLPattern('https://example.com/api/users/:userId/profile'); const matcher = pattern.exec('https://example.com/api/users/123/profile'); console.log(matcher.pathname.groups.userId); // 123
const pattern = new URLPattern('https://example.com/api/users/:userId/profile');
const matcher = pattern.exec('https://example.com/api/users/123/profile');
console.log(matcher.pathname.groups.userId); // 123

عملکرد exec در URLPattern

هنگامی که متد

exec
exec را روی یک
URLPattern
URLPattern فراخوانی می‌کنیم، به یک URL معتبر نیاز دارد. این متد یک آبجکت matcher برمی‌گرداند که شامل ویژگی‌هایی برای هر بخش از URL (مانند
protocol
protocol،
host
host،
pathname
pathname و غیره) است.

هر یک از این ویژگی‌ها دارای یک ویژگی

groups
groups هستند که نام placeholderها (مانند
:userId
:userId) را به مقادیر آن‌ها در URL نگاشت می‌کند.

اگر فقط بخواهیم یک بخش خاص از URL، مانند نام مسیر را تطبیق دهیم، می‌توانیم از کاراکترهای wildcard (مانند

*
*) در الگوی URL استفاده کنیم. همچنین، به جای استفاده از یک رشته URL، می‌توانیم یک آبجکت حاوی بخش‌هایی از URL که می‌خواهیم تطبیق دهیم، ارسال نماییم:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
new URLPattern('https://*/api/users/:userId/profile');
new URLPattern({ pathname: '/api/users/:userId/profile' });
new URLPattern('https://*/api/users/:userId/profile'); new URLPattern({ pathname: '/api/users/:userId/profile' });
new URLPattern('https://*/api/users/:userId/profile');
new URLPattern({ pathname: '/api/users/:userId/profile' });

API

URLPattern
URLPattern هنوز در تمام مرورگرها قابل استفاده نیست. در زمان نوشتن این مطلب، مرورگرهای Firefox و Safari از آن پشتیبانی نمی‌کنند. برای مشاهده آخرین وضعیت پشتیبانی مرورگرها می‌توانیم به وب‌سایت CanIUse.com مراجعه کنیم.

جمع‌بندی

API

URL
URL یک ابزار چندمنظوره برای ساخت، اعتبارسنجی و مدیریت URLها در جاوااسکریپت است. استفاده از این API نسبت به روش‌های دستی یا regular expressionها ایمن‌تر و کم‌خطاتر است. همچنین با استفاده از آبجکت
URLSearchParams
URLSearchParams می‌توانیم بدون نگرانی درباره اتصال رشته‌ها یا کدگذاری کاراکترهای خاص، به راحتی یک query string بسازیم.

دیدگاه‌ها:

افزودن دیدگاه جدید