Jak používat funkci bez serveru jako proxy pro ukládání obrázků / mezipaměti

Dnes jsem opravil nepříjemnost v jednom z mých vedlejších projektů Tiny Helpers. Tiny Helpers je sbírka zdrojů bezplatných online vývojářských nástrojů. Stránka obsahuje snímky obrazovky nástroje a, je-li k dispozici, profilový obrázek správce GitHub.

A tyto profilové obrázky byly problémem; když jste procházeli webem, vyžádali jste si mnoho profilových obrázků na GitHubu a nakonec se přestaly zobrazovat.

Tak co se tam děje? Odpověď lze nalézt na panelu sítě nástrojů pro vývojáře.

GitHub omezuje požadavky na profilové obrázky, když jich vytváříte příliš mnoho. Nepodařilo se mi najít přesné limity sazeb, ale jedna věc je jasná, čím více projektů bude uvedeno na Tiny Helpers, tím rychleji návštěvníci na tyto limity narazí.

Naštěstí vám s tímto problémem může pomoci moderní hosting!

Proxy serveru bez serveru/ukládání do mezipaměti

Tiny Helpers je hostován na Vercelu. Vercel poskytuje funkce CI/CD, CDN a také funkce bez serveru. Přetáhněte soubor do /api adresář projektu, napište nějaký JavaScript a začněte zadávat požadavky na vaše nové API!

Samotný koncový bod API však nepomohl s problémem limitu rychlosti GitHubu. Potřeboval jsem způsob, jak snížit počet požadavků, a tady přichází do hry Vercel's Edge Caching. Můžete nejen nasadit funkce bez serveru, ale také instruovat Vercel, aby uložil odpovědi do mezipaměti na jejich okrajové síti. Vše, co potřebujete, je definovat cache-control záhlaví!

Se všemi těmito funkcemi bych mohl:

  • Nasaďte nový koncový bod rozhraní API, který přijímá parametry dotazu pro uživatele a velikost obrázku profilu (/api/user-image/?stefanjudis&size=40 ).
  • Načítání a proxy profilové obrázky GitHubu ve funkci bez serveru.
  • Uložte do mezipaměti odpovězený obrázek, abyste mohli uložit požadavky na GitHub.

A tady je kód, aby to všechno fungovalo.

// /api/image.js

// `got` streamlines Node.js request handling
const got = require('got');

module.exports = async (req, res) => {
  try {
    const { user, size } = req.query;
    const GITHUB_URL = `https://github.com/${user}.png${
      size ? `?size=${size}` : ''
    }`;
    const imageRequest = got(GITHUB_URL);

    // Use the `got` promises to:
    //   1. receive the content type via `imageResponse`
    //   2. receive the buffer via `imageBuffer`
    const [imageResponse, imageBuffer] = await Promise.all([
      imageRequest,
      imageRequest.buffer(),
    ]);

    // Define a caching header to cache the image on the edge
    // FYI: Caching is tricky, and for now, I went with 12h caching time
    // There might be better configurations, but it does the trick for now
    // 
    // Read more: https://vercel.com/docs/concepts/functions/edge-caching
    res.setHeader('Cache-Control', 's-maxage=43200');
    res.setHeader('content-type', imageResponse.headers['content-type']);
    res.send(imageBuffer);
  } catch (error) {
    // Handle thrown 404s
    if (error.message.includes('404')) {
      res.status(404);
      return res.send('Not found');
    }

    // Fail hard if it's not a 404
    res.status(500);
    res.send(error.message);
  }
};

Nasazení mého nového image proxy mi trvalo třicet minut. Se všemi těmito novými nástroji v našem nástrojovém pásu je skvělý čas být vývojářem frontendu. ♥️