for example, if you are doing some kind of eval
on a string generated elsewhere
(assumes your Object is JSON-serializable)
The Problem
there’s a lot that can go wrong with a naive approach:
- if you simply inject the result of
toString
, you may have issues deserializing later- you may be tempted to pass a “simple” number between contexts, but does your parser correctly handle:
NaN
,Infinity
, negatives, decimals? - you will probably end up with something like
[object Object]
for non-trivial types
- you may be tempted to pass a “simple” number between contexts, but does your parser correctly handle:
- if you simply inject the result of
JSON.stringify
, you will have issues with newlines, delimiters, quotes, escaping, etc. - if you simply inject the result of
btoa
, you will have issues with Unicode
The Solution
// on the backend
const object_for_frontend = { myCoolParams: true }
function bytesToBase64 (bytes) {
return btoa(Array.from(bytes, function (byte) {return String.fromCodePoint(byte);}).join(""))
}
const b64params_for_frontend = bytesToBase64(new TextEncoder().encode(JSON.stringify(object_for_frontend)))
const str_for_eval = `object_from_backend = JSON.parse(new TextDecoder().decode(base64ToBytes("${b64params_for_frontend}")))`
// on the frontend
// (you could embed the below function in your "str_for_eval" above if you want)
function base64ToBytes (base64) {
return Uint8Array.from(atob(base64), function (m) {return m.codePointAt(0);})
}
eval(str_for_eval)
// object_from_backend === { myCoolParams: true }