Explore front-end black technology-cache data through rgba value of png graph

  canvas, frontend, html5, http, node.js

This article is original, welcome to reprint, reprint please indicate the author’s information
Project address:SphinxJS
Online experience address:https://jrainlau.github.io/sp …

Speaking of front-end caching, most people think of only a few conventional schemes, such ascookie,localStorage,sessionStorage, or addindexedDBAndwebSQL, andmanifestOffline cache. In addition, is there any other way to cache the front-end data? This article will take you to explore how to cache data step by step through the rgba value of png graph.

PS: The content studied in this paper has been integrated into an open source JS library, whose name isSphinxJSInterested students can move to this articleSphinx JS-An Ultralight Open Source Library Encoding String into png PicturesLook at the relevant documents, welcome STAR!

principle

We know that by setting up for static resourcesCache-ControlAndExpiresThe response header can force the browser to cache it. When the browser makes a request to the background, it will first look in its own cache. If there is no such request in the cache, it will continue to request this static resource from the server. Using this, we can store some information that needs to be cached through this static resource caching mechanism.

So how do we write information into static resources?canvasProvided.getImageData()Methods and.createImageData()Methods can be used toreadAndSet upPhotographicrgbaValue. So we can use these two API to read and write information.

Next, look at the schematic diagram:

图片描述

When static resources enter the cache, any future requests for the picture will first look up the local cache, which means the information has already been cached locally in the form of a picture.

Note that due torgbaThe value can only be an integer between [0, 255], so the method discussed in this paper is only applicable to data composed of pure numbers.

Static server

We usenodeBuild a simple static server:

const fs = require('fs')
 const http = require('http')
 const url = require('url')
 const querystring = require('querystring')
 const util = require('util')
 
 const server = http.createServer((req, res) => {
 let pathname = url.parse(req.url).pathname
 let realPath = 'assets' + pathname
 console.log(realPath)
 if (realPath !  == 'assets/upload') {
 fs.readFile(realPath, "binary", function(err, file) {
 if (err) {
 res.writeHead(500, {'Content-Type': 'text/plain'})
 res.end(err)
 } else {
 res.writeHead(200, {
 'Access-Control-Allow-Origin': '*',
 'Content-Type': 'image/png',
 'ETag': "666666",
 'Cache-Control': 'public, max-age=31536000',
 'Expires': 'Mon, 07 Sep 2026 09:32:27 GMT'
 })
 res.write(file, "binary")
 res.end()
 }
 })
 } else {
 let post = ''
 req.on('data', (chunk) => {
 post += chunk
 })
 req.on('end', () => {
 post = querystring.parse(post)
 console.log(post.imgData)
 res.writeHead(200, {
 'Access-Control-Allow-Origin': '*'
 })
 let base64Data = post.imgData.replace(/^data:image\/\w+;  base64,/, "")
 let dataBuffer = new Buffer(base64Data, 'base64')
 fs.writeFile('assets/out.png', dataBuffer, (err) => {
 if (err) {
 res.write(err)
 res.end()
 }
 res.write('OK')
 res.end()
 })
 })
 }
 })
 
 server.listen(80)
 
 console.log('Listening on port: 80')

The function of this static resource is very simple. It provides two functions: to generate pictures through base64 from the client and save them to the server; Set the cache time of the picture and send it to the client.

The key part is to set the response header:

res.writeHead(200, {
 'Access-Control-Allow-Origin': '*',
 'Content-Type': 'image/png',
 'ETag': "666666",
 'Cache-Control': 'public, max-age=31536000',
 'Expires': 'Mon, 07 Sep 2026 09:32:27 GMT'
 })

We have set up this picture for a year.Content-TypeAnd ten yearsExpiresIn theory, it is long enough. Let’s start coding the client.

Client

<!  --  client.html -->
 
 <canvas id="canvas" width="8", height="1"></canvas>

Suppose we need to store 32 bits of data, so we set the width to 8 and the height to 1 for canvas. Why is the corresponding length of 32-bit data 8, because every pixel has onergba, corresponding tored,green,blueAndalpha4 values, so divide by 4.

<!  -- client.js -->
 
 let keyString = '01234567890123456789012345678901'
 
 let canvas = document.querySelector('#canvas')
 let ctx = canvas.getContext('2d')
 
 let imgData = ctx.createImageData(8, 1)
 
 for (let i = 0;   i < imgData.data.length;  i += 4) {
 imgData.data[i + 0] = parseInt(keyString[i]) + 50
 imgData.data[i + 1] = parseInt(keyString[i + 1]) + 100
 imgData.data[i + 2] = parseInt(keyString[i + 2]) + 150
 imgData.data[i + 3] = parseInt(keyString[i + 3]) + 200
 }
 
 ctx.putImageData(imgData, 0, 0)

First, let’s assume that the string to be cached is 32-bit01234567890123456789012345678901And then we use.createImageData(8, 1)Generate a blankimgDataObject. Next, we assign a value to this empty object. In order to make the experiment more intuitive, we are rightrgbaThe values have been amplified. It’s set upimgDataLater, through.putImageData()Methods Put it into our canvas.

We can print it now and look at thisimgDataWhat is it:

// console.log(imgData.data)
 
 [50, 101, 152, 203, 54, 105, 156, 207, 58, 109, 150, 201, 52, 103, 154, 205, 56, 107, 158, 209, 50, 101, 152, 203, 54, 105, 156, 207, 58, 109, 150, 201]

Next, we will compile this canvas into base64 of a picture and send it to the server. At the same time, we will receive the server’s response and cache the picture:

$.post('http://xx.xx.xx.xx:80/upload', { imgData: canvas.toDataURL() }, (data) => {
 if (data === 'OK') {
 let img = new Image()
 img.crossOrigin = "anonymous"
 img.src = 'http://xx.xx.xx.xx:80/out.png'
 img.onload = () => {
 Log ('Complete Picture Request and Caching')
 ctx.drawImage(img, 0, 0)
 console.log(ctx.getImageData(0, 0, 8, 1).data)
 }
 }
 })

The code is very simple, through.toDataURL()The method sends base64 to the server, which generates and returns a picture after processing. Its picture resource address ishttp://xx.xx.xx.xx:80/out.png. Inimg.onloadAfter that, in fact, the pictures have already been cached locally. We printed out the picture information in this event as a comparison with the source data.

Result analysis

Start the server and run the client. When loading for the first time, you can see the response picture information through the console:

图片描述

200 OK, which proves that the image was obtained from the server.

Close the current page and reload:

图片描述

200 OK (from cache), proving that the picture was read from the local cache.

Let’s look at it directly.rgbaComparison of values:

Source data: [50, 101, 152, 203, 54, 105, 156, 207, 58, 109, 150, 201, 52, 103, 154, 205, 56, 107, 158, 209, 50, 101, 152, 203, 54, 105, 156, 207, 58, 109, 150, 201]
 
 Cache data: [50, 100, 152, 245, 54, 105, 157, 246, 57, 109, 149, 244, 52, 103, 154, 245, 56, 107, 157, 247, 50, 100, 152, 245, 54, 105, 157, 246, 57, 109, 149, 244]

As you can see, the source data and cache dataBasically the sameInalphaThe value of the error is too large, inrgbWithin valueOccasional error. Through analysis, it is believed that the cause of the error is that the operation involved in the process of base64 to buffer will cause the data to change. This pointTo be verified.

According to the previous conclusion, the reason for the error between the source data and the cache data is determined as follows after verificationalphaDue to the interference of the value. If we putalphaThe value is directly set to 255 and only the data is stored in thergbValue, the error can be eliminated. The following are the improved results:

Source data: [0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 0, 255, 2, 3, 4, 255, 6, 7, 8, 255, 0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 0, 255]
 
 Cache data: [0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 0, 255, 2, 3, 4, 255, 6, 7, 8, 255, 0, 1, 2, 255, 4, 5, 6, 255, 8, 9, 0, 255]

Because I’m lazy, I just putalphaThe value is given as 255 without updating the logic of loop assignment, so the metadata of bit 4n is directly replaced with 255, which is reservedReaders can modify it by themselves.Change again when you are free.

To sum up, this black technology that uses rgba value of png graph to cache data is theoretically feasible.However, in the actual operation process, more influencing factors may need to be considered, such as trying to eliminate the errors of the server and adopting fault tolerance mechanism.In fact, it is also feasible.

It is worth noting that,localhostIt is possible that resources will be requested directly through the local instead of the server by default, so in the local experiment, it can be done by setting the header.corsCross domain and simulate server access by setting IP address and 80 ports.

Postscript

Black technology, in fact, the principle is very simple, similar to and throughEtagMethods such as strong cache. The purpose of the research is only to learn, and should never be used illegally. If readers find any mistakes or omissions in this article, they are welcome to correct them and hope that interested friends can discuss them together.

Thank you for reading. I am Jrain, welcome to pay attention.My column, will not regularly share their learning experience, development experience, carrying dry goods outside the wall. See you next time!