There are different ways to utilize Cloudflare workers to implement ImageEngine. In the following we'll see how workers can be used together with Workers Routes to serve images from ImageEngine.
A "Worker Route" is basically a specific url pattern that will trigger the execution of the worker. The worker will then proxy the optimized image through to the end user.
This has the advantage of serving the images from your main domain, so that the browser doesn't need to connect to the ImageEngine delivery address. Saving valuable milliseconds of networking.
This setup is usually not something we recommend and should be used with caution. However, thanks to Cloudflare's cache API, we can construct pretty safe keys for the optimized images so that images can be cached on the Cloudflare infrastructure.
Note: The domain must be fully enabled with both DNS and HTTP Proxy (CDN) in Cloudflare for Workers to work.
ImageEngine will act as the origin seen from the edge. ImageEngine is configured with the actual origin. In other words, the worker acts as a proxy.
Preparation
- Sign up for an ImageEngine account and get a delivery address for your images, if you don't already have one.
- Verify the setup by accessing images like this:
xyz123.cdn.imgeng.in/path/image.jpeg
Cloudflare configuration
Cloudflare offers several ways to invoke a worker. In the following example, we'll use Cloudflare's Worker Routes.
The main goal is to be able to serve images from the same domain as the website.
For example, you can make a route wich catches all requests to /images/*
and execute the worker.
But first, we'll have to create the worker.
Set up the worker
Log on to dash.cloudflare.com and go to the Workers section
Click "Create new Service". Give your worker a name, and confirm by clicking "Create service"
Next, we can define how this worker should be triggered. Navigate to the "Triggers" tab.
In the example above, all images will be referenced with the path /images/
. Which means that your html looks something like this: <img src="/images/more/path/image.jpg">
Finding a suitable trigger route depends on how your website is built. For Wordpress for example, it may make sense to use /wp-content/uploads/*
because all images are stored there.
You can add any kind of identifier to the trigger. It doesn't have to exist in the actual origin url to the images. The imageEngine will remove the trigger from the path. (Feel free to customize the code below to make it fit your needs). You can add multiple trigger routes.
Now, we can define some environment variable that the worker will need. Go to the "Settings" tab and click "Environment Variables"
Add the variables:
IMAGEENGINE_DELIVERY_ADDRESS
: This is the delivery address provided by ImageEngineTRIGGER_PATH
: This is the path triggering the worker. In the example above we used "/images/". To follow the example, the value should be "images". Note that the worker code below, will remove the value of this variable from the actual origin url.
Click Save.
Code sample
The actual worker code can be edited in the web browser or using Wrangler CLI. For now, we can use the online editor to paste in the code below:
Copy and pate the code below into the editor:
(() => { (() => { addEventListener("fetch", (event) => { event.respondWith(handleRequest(event)); }); async function serveAsset(event) { const request = event.request; //Get the requested url and any url params const url = new URL(request.url); let path = url.pathname + url.search; /* Remove the path identifier from the origin path and construct the ImageEngine address. NOTE: If your trigger path is the actual location of the images, like with Wordress (/wp-content/uploads/*), you may remove this line below. */ path = path.replace(new RegExp(TRIGGER_PATH,"g"), ""); const imageEngineURL = `http://${IMAGEENGINE_DELIVERY_ADDRESS}${path}`; let headers = new Headers(new Map(request.headers)); //gather important headers to be used in the Cloudflare cache key: const ch_width = request.headers.get("sec-ch-width"); const ch_dpr = request.headers.get("sec-ch-dpr"); const ch_vp_width = request.headers.get("sec-ch-viewport-width"); const ch_ect = request.headers.get("ect"); const ch_save_data = request.headers.get("save-data"); const ch_user_agent = request.headers.get("user-agent"); const ch_ua = request.headers.get("sec-ch-ua"); //use the headers to compute a cache key along with the requested url const ieCacheKey = `${url}${ch_width}${ch_dpr}${ch_vp_width}${ch_ect}${ch_save_data}${ch_user_agent}${ch_ua}`; //check if the request is cached const cache = caches.default; let ieresponse = await cache.match(ieCacheKey); if (!ieresponse) { let q = url.search ? '&' : '?'; let missurl=imageEngineURL+q+'v='+new Date().getTime(); console.log("missurl: "+missurl); //fetch optimized image from ImageEnngine ieresponse = await fetch(missurl, { headers }); //prepare response for cache ieresponse = new Response(ieresponse.body, ieresponse); ieresponse.headers.set("cf", {cacheTtl: 86400,cacheKey: ieCacheKey,cacheEverything: false}); ieresponse.headers.set("server", "ScientiaMobile ImageEngine"); event.waitUntil(cache.put(ieCacheKey, ieresponse.clone())); } //remove cf header ieresponse = new Response(ieresponse.body, ieresponse); ieresponse.headers.set("server", "ScientiaMobile ImageEngine"); ieresponse.headers.delete("cf"); return ieresponse; } async function handleRequest(event) { if (event.request.method === "GET") { let response = await serveAsset(event); if (response.status > 399) { response = new Response(response.statusText, { status: response.status }); } return response; } return new Response("Method not allowed", { status: 405 }); } })(); })();
Here you can test the worker by making a request to an image on your site with the correct trigger value in the path. The Worker will read the Environment Variables that are referenced in the code.
Once verified, click "Save and Deploy".
Conclusion
Now, your website serves optimized images using ImageEngine but leveraging Cloudflares network of edge cache. More importantly however, is that no additional connection is needed to the ImageEngine delivery address. This can save a lot of time in connection setup.
Comments
0 comments
Please sign in to leave a comment.