ساخت یک Cors Proxy با Cloudflare Workers

ساخت یک Cors Proxy با Cloudflare Workers

توی پروژه های فرانت اند  احتمالا موقع کار با  API تا حالا به خطایی شبیه به این برخورد کردید:

این خطا به این دلیله که سمت سرور (اونجایی که  بهش ریکوئست میفرستید)  یک پارامتر در قسمت Header در Response به نام Access-Control-Allow-Origin  روی درخواست هایی که بهش فرستاده میشه ست میکنه و با استفاده از این پارامتر مشخص میکنه که  از چه origin و یا در واقع از چه آدرسی میشه بهش Request فرستاد و  اگر آدرس دیگه ای باشه این درخواست انجام پذیر نخواهد بود.

به عنوان مثال اگر از لوکال هاست خودتون به یک API درخواست ارسال کنید، مرورگر (کروم، فایرفاکس و...) توی درخواست هاتون این Header رو اضافه میکنن:

Origin: http://localhost:3000

دلیل این که شما این با این خطا مواجه میشید اینه که سروری که بهش درخواست میفرستید اون مقدار Header رو ست نکرده و یا مقداری داره که  با Origin شما مغایرت داره (مثلا شما از سیستم لوکال دارید برنامه تون رو تست میکنید)، در هر صورت این ارور اکثر وقت ها اذیت کننده  و در ادامه قراره راه حلش رو با هم دیگه بررسی کنیم.

راه حل اول

اولین روش اینه که اگر به سرور API تون دسترسی دارید مقدار Access-Allow-Origin رو توی کد بکند مقداری رو بزارید که بتونید بهش دسترسی داشته باشید، اگر مقدار * رو بهش بدید، از هر Origin ای قابل دسترسیه و خب ممکنه امنیت اون API پایین بیاد (البته خیلی ها همین کار میکنن).

راه حل دوم

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

راه حل سوم

بعضی افراد اومدن یک Cors Proxy ساختن که شما با استفاده از اون میتونید این خطا رو دور بزنید:

https://api.allorigins.win/raw?url={{yourUrl}}

توی آدرس بالا جای {{yourUrl}} آدرس خودتون رو بنویسید، در نهایت با استفاده از سایت بالا اگر API رو کال کنید دیگه خطای Cors دریافت نمی کنید.

راه حل چهارم

راه آخر اینه که خودتون یک Cors Proxy بسازید،  میتونید با هر زبان برنامه نویسی سمت Backend  و روی هر سروری که خواستید کد پروکسی تون رو بنویسید و  اجرا کنید و بعد از اون با آدرس سرور خودتون مشابه روش سوم Request هاتون رو بفرستید. من اینجا از Nodejs استفاده میکنم و کد خودم رو روی Cloudflare Workes ران میکنم.

نسخه ی رایگان بهتون 100 هزار ریکوئست به همراه 10 میلی ثانیه cpu به ازای هر درخواست رو بهتون میده، جزئیات دیگه رو میتونید از اینجا بخونید.

مراحل زیر رو طی کنید:

  1. وارد سایت بشید و یک اکانت بسازید (اینجا)
  2. وارد داشبورد بشید و  از منوی سمت چپ روی Workers & Pages کلیک کنید، توی صفحه ی باز شده روی Create Application کلیک کنید.
  3. توی صفحه ی باز شده روی Create Worker کلیک کنید.

 4. یک اسم دلخواه دلخواه انتخاب کنید و روی Deploy کلیک کنید.

5. توی صفحه ی جدید روی Edit Code کلیک کنید، توی فایل Worker.js کد زیر رو جایگزین کد قبلی کنید و روی Save And Deploy کلیک کنید.

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  try {
    const url = new URL(request.url);

      const { searchParams } = new URL(request.url)
  let name = searchParams.get('name')

    if (url.pathname === "/") {
      return new Response(`{"usage": "${url.origin}/<url>"}`);
    }

    function addHeaders(response) {
      response.headers.set("Access-Control-Allow-Origin", "*");
      response.headers.set("Access-Control-Allow-Credentials", "true");
      response.headers.set("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
      response.headers.set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    }
    
    let response;
    if (request.method == "OPTIONS") {
      response = new Response("");
      addHeaders(response);
      return response;
    }

    response = await fetch(request.url.slice(url.origin.length + 1), {
        method: request.method,
        headers: request.headers,
        redirect: "follow",
        body: request.body
    });
    response = new Response(response.body, response)
    addHeaders(response);
    return response;
  } catch (e) {
    return new Response(e.stack || e, {status: 500});
  }
}

حالا آدرسی که بهتون داده (آخرش با workers.dev تموم میشه) رو میتونید جلوی هر آدرسی که میخواین ریکوئست بزنید بزارید، درخواست های Get و Post و... و هر Body و Header ای که به این آدرس بدین به آدرس اصلی پورت میشه و هر Response ای هم که باشه عینا بهتون میده. مثلا عکس زیر برای تستی هست که من با ورکر خودم انجام دادم:

سخن پایانی

میتونید این اسکریپت رو روی سرور خودتون هم ران کنید و حتی کد رو هم برای استفاده ی خاص خودتون تغییر بدید.یکی از کاربرد های خوب دیگه ای که میتونید از این مدل پروکسی ها داشته باشید اینه که برای مثال اگر عکس هایی که توی سایت تون استفاده میکنید رو روی سرور خودتون آپلود نمی کنید (برای مثال از Cloudinary استفاده می کنید)، چون این عکس ها Origin شون با سایت شما فرق داره مرورگر یک درخواست Preflight  قبل از درخواست  اون عکس میفرسته تا مطمئن بشه این درخواست  معتبر هست یا نه که این کار باعث میشه لود شدن اون عکس بیشتر طول بکشه و  باعث مشکلاتی مثل LCP بشه و به سئوی سایتتون صدمه بزنه. کاری که میتونید بکنید اینه که این پروکسی رو روی سرور خودتون اجرا کنید و به جای این که مستقیما به یک هاست خارحی ریکوئست بفرستید به این پروکسی که از Origin خودتون هست درخواست بفرستید و اون عکس ها رو لود کنید، اینجوری مروگر چون با یک درخواست از Origin خودتون مواجه میشه دیگه اون درخواست Preflight رو ارسال نمیکنه.

آپدیت

توی نسخه 113 گوگل کروم ک به تازگی منتشر شده شما میتونید مقدار Access-Control-Allow-Origin رو توی کروم به صورت دستی تغییر بدید که میتونید از اینجا یاد بگیرید که چجوری میشه این کار رو انجام داد.

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