更多会员限定文章可以到patreon观看
完整code可以到以下gist
Client端HTML
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> img { width: 150px; } </style></head><body> <input type="file" id="file-uploader" accept="image/png" multiple="multiple"/> <img id='preview'> </body></html>
input tagtype设成file,让使用者能选择档案accept设定使用者能选的格式,如果要所有照片格式就改成image/*
multiple让使用者能选择多个档案Client端JS
我们会用JSON来传递资料(也可以用form-data)
取得使用者选择的照片
读进来的每个档案会是blob(Binary Large Object)
const fileUploader = document.querySelector('#file-uploader');fileUploader.addEventListener('change', (e) => { console.log(e.target.files); // get list of file objects});
e.target.files
是fileList
将照片转成base64 string
function display_img(curFiles) { const curFile = curFiles[0]; const reader = new FileReader(); // 这会在readAS后才执行 reader.onload = function (e) { // console.log('file:', e.target.result); // base64 document.querySelector('#preview').src = e.target.result; }; // to data url reader.readAsDataURL(curFile);}
img.src
能显示url with base64
将blob转成array buffer
相较于buffer, blob保留了照片的资讯,像是档名、MIME type等
function blob2buffer(blob) { return new Promise((resolve, reject) => { var arrayBuffer; var fileReader = new FileReader(); fileReader.onload = function (event) { arrayBuffer = event.target.result; resolve(arrayBuffer); }; fileReader.readAsArrayBuffer(blob); return arrayBuffer; });}
先将blob转成buffer,方便后续建成array
将array转成字串post到server
buffer不能直接操作,要先转成指定type的array
arrayBuffer = await blob2buffer(pic);fetch(url, { method: 'POST', // flask need to set header of json headers: { 'content-type': 'application/json' }, body: JSON.stringify({ item_id: 1, format: 'png', img: Array.from(new Uint8Array(arrayBuffer)), }),})
转成array前要先将buffer转成typed array
读取server端传回来的array
产生blob的url (不同于前面产base64的fileReader)
function display_arr_img(arr) { document.querySelector('#preview').src = URL.createObjectURL(new Blob([new Uint8Array(arr)], {type: "image/png"}));}
将array转回typed array,再将其变回blob
Server端API
这里我们用python + flask作为例子
DataBase
这里我们用MySQL,然后照片的栏位type是blob,要注意blob有分可以存的size
TINYBLOB
: maximum length of 255 bytesBLOB
: maximum length of 65,535 bytes => 64kbMEDIUMBLOB
: maximum length of 16,777,215 bytesLONGBLOB
: maximum length of 4,294,967,295 bytes连接到资料库
import pymysqlconnection = pymysql.connect(host='localhost', user='root', password='password', db='db01', charset='', cursorclass=pymysql.cursors.DictCursor)
注意pymysql不支援connection string
Python Code
所需套件在requirements.txt内
存到blob的好处是不会让照片被额外index (会导致档案大小增幅30%)
@app.route('/upload/json/img_raw', methods=['POST'])def raw_img(): json_data = flask.request.json # save to db with connection.cursor() as cursor: sql = "UPDATE table1 SET `img_raw`=%s WHERE id=%s" try: # img现在是list, 可以用json string/ byterarray/ base64存进资料库 cursor.execute(sql, (json.dumps(json_data['img']), json_data['item_id'])) connection.commit() except Exception as err: connection.rollback() return flask.jsonify({'err': err}) # get a picture sql = "SELECT * FROM table1" cursor.execute(sql) result = cursor.fetchone() r = result[0]['img_raw'] r = json.loads(r.decode()) # utf-8, 也可用ascii return flask.jsonify({'img': r})
存进mysql blob栏位后,会变成binary object
json.dumps(json_data['img']
我们要将List转成json style的string才能存进资料库json.loads(r.decode())
存资料库拿出来的会是binary object,我们要先将其转回字串然后再将字串 parse回list