场景: 最近在做一个特定的项目中(Content-Security-Policy
)只能通过图片中获取动态信息,然后搜遍了百度,试了好几种方法,并整理了出来方便后人采坑
吐槽一下,百度搜到10篇有9篇都是复制粘贴的,毫无参考意义,想不懂为什么会有这样的操作,每次搜到一样的都想骂人
获取图片数据流信息
做法是让后台生成图片的时候把信息写入到图片里面,然后前端解析这张图片去获取
/**
* 获取图片数据(二进制数据流)
* @param {string} src 请求图片路径
* @param {(code: string) => void} callback 回调函数
*/
function getImageData(src, callback) {
const XHR = new XMLHttpRequest();
XHR.open('GET', src, true);
XHR.responseType = 'arraybuffer';
XHR.overrideMimeType('text/plain; charset=x-user-defined');
XHR.onreadystatechange = function () {
if (XHR.readyState === 4 && XHR.status === 200) {
const file = XHR.response || XHR.responseText;
const blob = new Blob([file], { type: 'image/jpeg' });
const fr = new FileReader();
// console.log('Blob', blob);
fr.readAsText(blob);
fr.onload = function (e) {
/** @type {string} */
const code = e.target.result;
// console.log(code);
if (typeof callback === 'function') callback(code);
}
}
}
XHR.send();
}
这样会有一个问题,就是在 Content-Security-Policy
任何 http
请求都会给拦截,所以这个方法不通过,github
上有个叫 exif-js
的库,具体实现也是 http
请求修改响应类型实现的。
最后想到可以用二维码的方式,然后提取二维码里面的内容去实现 最后无意间发现有一个叫 qrcode
的东西(注意这个跟 github 上搜到的 qrcode.js
不是同一个东西),完美的解决了这个问题。步骤是先用 img
加载一张图片(图片加载不会拦截)然后再用 canvas
转出到 base64
,最后解码读取。
实现代码
// 引入js
// <script src="qrcode.js"></script>
/**
* 获取图片base64
* @param {string} url 图片路径
* @param {(base64: string) => void} callback 回调
* @param {'jpg'|'png'} type 图片格式(可选)
*/
function getBase64(url, callback, type = 'jpg') {
const doc = document;
const canvas = doc.createElement("canvas");
const ctx = canvas.getContext("2d");
const img = new Image();
img.crossOrigin = 'Anonymous';
img.src = url;
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
const base64 = canvas.toDataURL('image/' + type);
if (typeof callback === 'function') callback(base64);
}
// doc.body.innerHTML = null;
// doc.body.appendChild(canvas);
}
const url = document.querySelector('.qrcode').src;
getBase64(url, base64 => {
qrcode.decode(base64);
qrcode.callback = function (res) {
// 这里二维码信息是加密过的,所以要解一下
console.log('二维码信息:', JSON.parse(atob(res)));
}
});
这样就完美绕开了 Content-Security-Policy
的拦截,因为图片加载不受限,而且这个库是纯算法读取二维码信息的,所以不需要 http
请求数据流。我稍稍对这个库做了一些调整,源码出处还不知道,如果知道的可以告诉我。