Images on CF

I want to store images on the server, and im using cloudflare workers with Hono.js. I can use their R2 Storage because it required credit card and unfortunately i don't have one:( also i cant use multer, as CF uses their own runtime (Workers runtime) so it does not support 'fs' module as of now... also i tried using Cloudinary and im getting some weird errors like "https not supported yet". So is there any way to store images in CF Workers? obv except base64 string...
8 Replies
rdutton
rdutton•5d ago
Not sure about hono.js, but this is a standard worker demo using KV for one file to keep it simple. It assumes PNG. KV on free has 1GB storage with each value up to 25MB. With high reads you'd want a CDN of some kind. const html_form = "<form method=post action='/' enctype='multipart/form-data'>Image Attachment<br/><input name='upload' type='file' accept='image/png'/><br/><button type=submit>Upload</button></form>"; function base64Encode (buf) { let string = ''; (new Uint8Array(buf)).forEach((byte) => { string += String.fromCharCode(byte)}); return btoa(string) } function base64Decode (string) { string = atob(string); const length = string.length; const buf = new ArrayBuffer(length); const bufView = new Uint8Array(buf); for (var i = 0; i < length; i++) { bufView[i] = string.charCodeAt(i) } return buf } export default { async fetch(request, env, ctx) { const url = new URL(request.url); if (url.pathname === '/test.png') { return new Response(base64Decode(await env.TESTKV.get("test.png")), { headers: { 'content-type': 'image/png' }, }); } let upload_detail = ""; if (request.method === 'POST') { const form = await request.formData(); const file = form.get('upload'); let value = await env.TESTKV.put("test.png", base64Encode(await file.arrayBuffer())); upload_detail = "File uploaded successfully<br/><img src='test.png'/>"; } return new Response(upload_detail + html_form, { headers: { 'content-type': 'text/html' }, }); } }; Sorry, just saw your comment re base64 and reading the docs, KV supports arrayBuffer, so updated version: const html_form = "<form method=post action='/' enctype='multipart/form-data'>Image Attachment<br/><input name='upload' type='file' accept='image/png'/><br/><button type=submit>Upload</button></form>"; export default { async fetch(request, env, ctx) { const url = new URL(request.url); if (url.pathname === '/test.png') { return new Response(await env.TESTKV.get("test.png", "arrayBuffer"), { headers: { 'content-type': 'image/png' }, }); } let upload_detail = ""; if (request.method === 'POST') { const form = await request.formData(); const file = form.get('upload'); let value = await env.TESTKV.put("test.png", await file.arrayBuffer()); upload_detail = "File uploaded successfully<br/><img src='test.png'/>"; } return new Response(upload_detail + html_form, { headers: { 'content-type': 'text/html' }, }); } };
UfoX1
UfoX1OP•5d ago
@rdutton Thanks!! It worked
rdutton
rdutton•4d ago
No probs 🙂
UfoX1
UfoX1OP•4d ago
btw do you know any other techniques to store images or files on a cloudflare? i guess storing base64 or arrayBuffer for all the images or files could be slow in a long run if application scales... i might be wrong im new to CF. correct me if im wrong:)
rdutton
rdutton•3d ago
The 2nd example avoids base64, so that is better and more efficient, however every request is still going to read from KV and incur cost in high volumes. To avoid that you will need utilise the Cloudflare cache. I haven't used it, but from what I can tell the cache is effectively a CDN you can manipulate via a worker. https://developers.cloudflare.com/workers/runtime-apis/cache/ const html_form = "<form method=post action='/' enctype='multipart/form-data'>Image Attachment<br/><input name='upload' type='file' accept='image/png'/><br/><button type=submit>Upload</button></form>"; export default { async fetch(request, env, ctx) { const url = new URL(request.url); if (url.pathname === '/test.png') { let cache = caches.default; const cache_response = await caches.default.match(request); if (cache_response) { return cache_response; } const response = new Response(await env.TESTKV.get("test.png", "arrayBuffer"), { headers: { 'content-type': 'image/png', 'Cache-Control': 's-maxage=10' }, }); await caches.default.put(request, response.clone()); console.log("Cache updated"); return response; } let upload_detail = ""; if (request.method === 'POST') { const form = await request.formData(); const file = form.get('upload'); let value = await env.TESTKV.put("test.png", await file.arrayBuffer()); upload_detail = "File uploaded successfully<br/><img src='test.png'/>"; } return new Response(upload_detail + html_form, { headers: { 'content-type': 'text/html' }, }); } }; Noting that you need to specify a cache-control header on the response stored using caches.default.put
UfoX1
UfoX1OP•3d ago
yeah i'll sure look into it btw thanks for the code and info you provided
rdutton
rdutton•2d ago
No probs at all. Been meaning to research the cache myself, looks to be quite useful.
UfoX1
UfoX1OP•2d ago
Yeah and also it's easy to implement with workers.

Did you find this page helpful?