ن
مقاله آموزشی

نمایش نرخ ارز زنده در سایت؛ سه روش با کد آماده

نویسنده: تیم نِت اَرز 1405/07/02 به‌روزرسانی: 1405/07/04 ۱۱ دقیقه مطالعه ۱۲ بازدید

مشتری وسط صفحهٔ محصول می‌پرسد «این قیمت با دلار چند حساب شده؟» و شما هر روز صبح عدد را دستی در یک فایل عوض می‌کنید. یا بدتر: فراموش می‌کنید و تا ظهر با نرخ دیروز می‌فروشید. یک تابلوی نرخ زنده همین را حل می‌کند، و ساختنش کار یک بعدازظهر است.

سه راه واقعی برای این کار وجود دارد و انتخاب بینشان به سایت شما بستگی دارد، نه به سلیقه. در این راهنما هر سه را با کدی که واقعاً روی وب سرویس نرخ ارز نِت اَرز اجرا می‌شود می‌نویسیم، و در آخر می‌گوییم کدام اشتباه‌ها سهمیهٔ روزانهٔ شما را بی‌دلیل تمام می‌کنند.

اول تصمیم بگیرید تابلو برای کیست

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

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

پیش از هر کد، یک اپ در پنل «API نرخ ارز» بسازید، دامنه‌تان را ثبت و تأیید کنید و کلید fx-ntz-v1-… را بردارید. مراحل کامل در شروع سریع مستندات آمده است. کلید به دامنهٔ شما قفل است، یعنی اگر کسی آن را از کد صفحه بردارد، روی دامنهٔ خودش کار نمی‌کند.

یک تصمیم دیگر هم از همین‌جا گرفته می‌شود: چند ارز می‌خواهید نشان بدهید و کدام عدد را. اگر فقط نرخ دلار برای محاسبهٔ قیمت لازم دارید، /rates/USD کافی است و پاسخ کوچک‌تری می‌گیرید. اگر تابلو می‌خواهید، یک درخواست به /rates?codes=… بزنید و همهٔ ارزها را با هم بگیرید؛ سه درخواست جدا برای سه ارز فقط سهمیه را سه برابر می‌کند.

روش ۱ — ویجت آماده، بدون کدنویسی

کم‌دردسرترین راه. یک تگ اسکریپت در جایی از قالب که می‌خواهید تابلو بنشیند:

<script src="https://netarz.ir/fx/widget.js"
        data-key="fx-ntz-v1-..."
        data-codes="USD,EUR,AED,TRY"
        data-theme="light"
        data-title="نرخ ارز امروز"
        async></script>

اسکریپت یک قاب (iframe) درست بعد از خودش می‌سازد و ارتفاعش را با محتوا تنظیم می‌کند. گزینه‌های پرکاربردش:

ویژگیکارپیش‌فرض
data-codesکدهای ارز با کاما، حداکثر ۱۲ تاارزهای پیش‌فرض اپ در پنل
data-themelight، dark یا goldlight
data-compactردیف‌های فشرده‌ترخاموش
data-changeنمایش یا حذف ستون تغییرنمایش
data-widthحداکثر عرض تابلو۴۲۰ پیکسل

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

<iframe src="https://netarz.ir/fx/embed?key=fx-ntz-v1-...&codes=USD,EUR&theme=gold"
        style="width:100%;max-width:420px;height:320px;border:0;border-radius:16px"
        loading="lazy" referrerpolicy="strict-origin-when-cross-origin" title="نرخ ارز"></iframe>

جزئیات همهٔ گزینه‌ها و رفتار تازه‌شدن در صفحهٔ ویجت آمده است.

روش ۲ — صدا زدن وب سرویس از مرورگر

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

const KEY = "fx-ntz-v1-...";           // domain-locked, safe to ship in the page
const API = "https://netarz.ir/api/fx/v1";

async function loadRates(codes = "USD,EUR,AED,TRY") {
  const res = await fetch(`${API}/rates?codes=${codes}`, {
    headers: { Authorization: `Bearer ${KEY}` },
  });

  if (!res.ok) {
    const { error } = await res.json();
    throw new Error(`${error.code}: ${error.message}`);
  }

  const { data, meta } = await res.json();

  document.querySelector("#fx-board").innerHTML = data
    .map((r) => `<tr><td>${r.name}</td><td>${r.buy.toLocaleString("fa-IR")}</td><td>${r.sell.toLocaleString("fa-IR")}</td></tr>`)
    .join("");

  const at = new Date(meta.as_of).toLocaleTimeString("fa-IR");
  document.querySelector("#fx-stamp").textContent =
    meta.is_delayed ? `نرخ ساعت ${at} (${meta.delayed_minutes} دقیقه تأخیر)` : `نرخ ساعت ${at}`;
}

loadRates();
setInterval(loadRates, 5 * 60 * 1000);   // every five minutes is plenty

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

روش ۳ — کش سمت سرور، پیشنهاد ما برای سایت پربازدید

اگر قیمت محصول به نرخ وابسته است یا بازدید سایت بالاست، نرخ را یک بار روی سرور بگیرید و همه از همان بخوانند. مزیتش سه چیز است: کلید هرگز به مرورگر نمی‌رسد، همهٔ کاربران یک عدد می‌بینند، و سهمیهٔ روزانه به‌جای هر بازدید، به هر چند دقیقه یک درخواست می‌رسد. در لاراول:

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;

function usdRate(): array
{
    return Cache::remember('fx.usd', now()->addMinutes(5), function () {
        $body = Http::withToken(config('services.netarz_fx.key'))
            ->timeout(8)
            ->retry(2, 400)
            ->get('https://netarz.ir/api/fx/v1/rates/USD')
            ->throw()
            ->json();

        return [
            'buy'   => $body['data']['buy'],
            'sell'  => $body['data']['sell'],
            'mid'   => $body['data']['mid'],
            'as_of' => $body['meta']['as_of'],
        ];
    });
}

اگر لاراول ندارید، یک فایل PHP ساده هم همین کار را می‌کند و بعداً در مقالهٔ اکسل و گوگل شیت هم به دردتان می‌خورد:

<?php
// rate.php — cache the board on disk and serve it to your own pages
$cache = __DIR__ . '/fx-cache.json';
$ttl   = 300; // seconds

if (!is_file($cache) || time() - filemtime($cache) > $ttl) {
    $ch = curl_init('https://netarz.ir/api/fx/v1/rates?codes=USD,EUR,AED,TRY');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 8,
        CURLOPT_HTTPHEADER     => ['Authorization: Bearer ' . getenv('NETARZ_FX_KEY')],
    ]);
    $body = curl_exec($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    // Only overwrite a good cache with a good answer.
    if ($code === 200 && $body) {
        file_put_contents($cache, $body, LOCK_EX);
    }
}

header('Content-Type: application/json; charset=utf-8');
echo file_get_contents($cache);

یادتان باشد برای فراخوانی از سرور، هدر Origin وجود ندارد؛ پس باید IP سرورتان را در پنل به فهرست IPهای مجاز اپ اضافه کنید، وگرنه پاسخ 403 origin_required می‌گیرید. قاعدهٔ کامل قفل دامنه در شروع سریع توضیح داده شده. اگر هنوز سروری ندارید، سرور مجازی چیست و دامنه و هاست خارجی نقطهٔ شروع خوبی هستند و پلن‌های آماده در دستهٔ سرور مجازی فهرست شده‌اند.

سه روش، کنار هم

معیارویجتفراخوانی از مرورگرکش سمت سرور
زمان راه‌اندازیچند دقیقهنیم ساعتیک تا دو ساعت
کنترل روی ظاهرمحدود به گزینه‌هاکاملکامل
کلید کجاستدر کد صفحه، قفل به دامنهدر کد صفحه، قفل به دامنهفقط روی سرور
مصرف سهمیههر بارگذاری و هر تازه‌شدنهر بازدیدکنندههر چند دقیقه، یک بار برای همه
دیده شدن عدد در گوگلخیر، داخل قاب استمعمولاً خیربله، در خود صفحه رندر می‌شود
مناسبوبلاگ و سایدبارمبدل و ماشین‌حسابفروشگاه و قیمت وابسته به نرخ

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

  1. گرفتن نرخ در هر بارگذاری صفحه. نرخ هر چند دقیقه عوض می‌شود، نه هر ثانیه. اگر روزی پنج هزار بازدید دارید و هر بازدید یک درخواست می‌فرستد، سهمیهٔ طرح رایگان تا ظهر تمام می‌شود.
  2. نبودن کش وقتی سرویس جواب نمی‌دهد. اگر پاسخ خطا بود، نرخ قبلی را نگه دارید و زمانش را نشان بدهید؛ صفحه‌ای که «خطا» می‌نویسد از صفحه‌ای که نرخ ده دقیقه پیش را با برچسب زمان نشان می‌دهد بدتر است.
  3. نادیده گرفتن as_of. این فیلد می‌گوید عددی که نشان می‌دهید مال چه لحظه‌ای است. نشان ندادنش یعنی کاربر نمی‌داند نرخ تازه است یا کهنه.
  4. چند ویجت در یک صفحه. هر کدام سهم خودش را از سهمیه برمی‌دارد. یک تابلو با چند ارز بگذارید، نه چند تابلو.

اگر می‌خواهید گوگل هم عدد را ببیند

این نکته معمولاً دیر فهمیده می‌شود: نرخی که داخل قاب ویجت می‌نشیند یا با جاوااسکریپت بعد از بارگذاری صفحه اضافه می‌شود، در بیشتر موارد بخشی از محتوای قابل ایندکس صفحهٔ شما نیست. اگر صفحه‌ای ساخته‌اید که هدفش دیده شدن در جست‌وجوی «نرخ ارز امروز» است، عدد باید در خود HTML صفحه رندر شود؛ یعنی روش سوم.

دو نکتهٔ تکمیلی هم دارد. زمان نرخ را در خود صفحه بنویسید تا هم کاربر و هم خزنده بدانند داده تازه است. و اگر صفحه کش می‌شود، مدت کش صفحه را با مدت کش نرخ یکی کنید؛ صفحه‌ای که ادعا می‌کند نرخ لحظه‌ای دارد ولی عددش مال دیروز است، هم اعتماد کاربر را می‌برد و هم چیزی به رتبه‌اش اضافه نمی‌شود.

تأخیر طرح رایگان را چطور بنویسید

در طرح رایگان، نرخی که می‌گیرید پانزده دقیقه عقب‌تر از لحظهٔ فعلی است: همان دقت، فقط با تأخیر. این را پنهان نکنید؛ یک خط کوچک زیر تابلو کافی است، مثل «نرخ ساعت ۱۴:۲۰ — با پانزده دقیقه تأخیر». دو فیلد meta.is_delayed و meta.delayed_minutes همین را به شما می‌گویند، پس متن را از خود پاسخ بسازید تا اگر روزی به طرح پرو رفتید، خودکار درست شود.

اگر کاری دارید که واقعاً به نرخ لحظه‌ای وابسته است، مثل یک داشبورد زنده یا هشدار قیمت، طرح پرو علاوه بر حذف تأخیر یک مسیر استریم هم دارد که به‌جای پرسیدن مکرر، هر تغییر را برای شما می‌فرستد. برای یک تابلوی معمولی سایت لازمش ندارید؛ برای داشبوردی که باید در لحظه تکان بخورد، همان چیزی است که مصرف سهمیه را منطقی نگه می‌دارد.

طرح رایگان روزانه ۳۰۰۰ درخواست دارد که با یک کش پنج‌دقیقه‌ای برای هر سایت معمولی کافی است. اگر نرخ زنده بدون تأخیر، تاریخچه، هشدار قیمت یا ویجت بدون برندینگ می‌خواهید، مقایسهٔ کامل دو طرح در صفحهٔ طرح‌ها آمده است. برای فهمیدن این‌که اصلاً عددی که نشان می‌دهید از کدام بازار می‌آید هم چهار نرخ ارز در ایران و تفاوت نرخ تتر و دلار آزاد را بخوانید. همین نرخ را در صفحهٔ گسترده هم می‌شود آورد؛ روشش در نرخ دلار در گوگل شیت و اکسل آمده و برای سایت‌های وردپرسی نرخ ارز در وردپرس و ووکامرس نسخهٔ آمادهٔ شورت‌کد دارد.

نمونه‌کد کامل و یک نکتهٔ IPv6

نسخهٔ کامل هر سه روش در مخزن netarz/fx-api-examples است: javascript/browser برای جدول نرخ در صفحه، php/rates.php برای PHP خالص با کش فایل و آخرین نسخهٔ سالم، و سرویس لاراول در laravel/. یک تفاوت کوچک با کدهای بالا دارند که ارزش دانستن دارد: درخواست سرور را روی IPv4 نگه می‌دارند. netarz.ir آدرس IPv6 هم دارد و سروری که هر دو نسخه را دارد ممکن است با IPv6 وصل شود؛ آن وقت IPv4ای که ثبت کرده‌اید دیده نمی‌شود. در PHP یک خط CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4 و در لاراول withOptions(['force_ip_resolve' => 'v4']) کافی است. افزونهٔ وردپرس و بقیهٔ مخزن‌ها در صفحهٔ کدهای متن‌باز نِت اَرز معرفی شده‌اند.

پرسش‌های پرتکرار

کلید API را در کد صفحه بگذارم امن است؟

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

با طرح رایگان می‌شود تابلوی نرخ ارز گذاشت؟

بله. طرح رایگان روزانه ۳۰۰۰ درخواست می‌دهد و نرخ‌ها پانزده دقیقه تأخیر دارند. با یک کش پنج‌دقیقه‌ای روی سرور، یک سایت معمولی خیلی زیر این سقف می‌ماند. ویجت رایگان هم یک خط «نرخ از نِت اَرز» با لینک نشان می‌دهد.

خطای 403 با کد origin_required یعنی چه؟

یعنی درخواست از سرور آمده و هدر Origin یا Referer ندارد. برای فراخوانی سمت سرور باید IP سرورتان را در پنل به فهرست IPهای مجاز اپ اضافه کنید. اگر پیام origin_not_allowed بود، یعنی دامنهٔ صفحه با دامنه‌های ثبت‌شدهٔ اپ نمی‌خواند.

هر چند وقت یک بار نرخ را تازه کنم؟

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

محصولات مرتبط با این مقاله

مطالب مشابه

نظر خوانندگان

هنوز نظری ثبت نشده. اگر این مقاله پرسشتان را جواب داد یا جای چیزی در آن خالی ماند، همین‌جا بنویسید.

نظرتان را بنویسید

این مقاله چقدر به کارتان آمد؟ (اختیاری)

نظرها را پیش از انتشار بررسی می‌کنیم. نقد صریح مشکلی ندارد؛ تبلیغ و توهین منتشر نمی‌شود.