I create apps for a living. Specifically, apps that run on a Set-Top Box –an embedded system with less RAM than a Raspberry Pi– rendering on a TV.
..to put it formally: I create React apps that runs on an ancient browser on top of a '90s' embedded system with lower specs than a Raspberry Pi, displayed on your TV.
yes, it's a challenge.
Right now we're building an 'Amazon'-like app: a grid of products. Using the TV remote you can move through the grid of products.
You get the idea.
Lately we've been playing with WebGL graphics. Using .path()
.fill()
on a <canvas>
is more perfomant than translating regular <div>
s!
We use pixi.js
: a –quote– "rendering system that uses WebGL (or optionally Canvas) to display images and other 2D visual content".
Hold on i'm getting there
To load the images, you need first to load on an Asset's cache like:
import { Assets } from 'pixi.js';
await Assets.load({
src: image.url,
alias: image.url,
loadParser: 'loadTextures',
});
Which is –checked in their GitHub– doing a regular GET
using fetch()
.
...
And that, led to CORS error cause Assets.load({ src })
is trying to fetch the resource from a server from a third party. And i have no control over this server.
CORS strikes back
CORS –yes there are millions of posts explaining CORS– CORS is expected.
Browsers, before making any request, send a pre-flight request (an HTTP OPTIONS
) asking the server: "ey buddy, I’d like to request this resource from you, and I’m from this origin, which is different from yours. is ok?"
If the server doesn’t explicitly allow the request from this "outsider" (i.e., by returning an Access-Control-Allow-Origin header
with the origin it agrees to), the browser itself blocks the request.
So, as an app, when I try to request something from a server, the browser ensures that the deal is consented.
How to solve CORS
The "ey, do you accept this request from this app?" check does not apply between two servers.
- browser → server: CORS applies.
- server → server: No CORS restrictions.
Memorable rule: Servers are a little bit racists, they don't trust browsers but are ok with other servers.
This is why the answer to CORS is: a proxy server.
Instead of having the app request the image directly from the third-party server, we have it go through our own server first (which we can configure to trust the "everything is good between us" check). This server then passes the request along to the third party.
In particular –do you remember we use a 2D graphics library bla bla bla– Assets.load()
does accept the raw base64 of the image.
So instead of using the fetch()
from the library we solved it doing the request ourselves and parsing the image as a base64 blob.
async function fetchImageThroughOurProxyServer(url) => {
const response = await fetch(url);
const arrayBuffer = await response.arrayBuffer();
const base64 = Buffer.from(arrayBuffer).toString('base64');
return `data:image/jpeg;base64,${base64}`;
};
async function fetchImage(image) {}
const blob = await fetchImageThroughOurProxyServer(image.url);
if (!blob) {
return null;
}
const src = URL.createObjectURL(blob);
return await Assets.load({ src, alias: image.url, loadParser: 'loadTextures' });
}
thanks for reading.
Top comments (0)