使用Node.js+Multer将图片以Blob存入MySQL后,无法通过Object URL显示图片的问题求助
使用Node.js+Multer将图片以Blob存入MySQL后,无法通过Object URL显示图片的问题求助
问题描述
我正在开发一个图片上传与展示功能:前端通过AJAX上传图片,后端用Express+Multer接收后将图片以Blob格式存入MySQL数据库,之后从数据库取出图片并在前端用Object URL显示。目前上传流程提示成功,但取出后图片无法正常显示,想请教问题出在哪里?
我的现有代码
1. 前端上传逻辑(index.html)
input.addEventListener('change', function () { uploadIMagetoDatabase(input.files[0]); getIMagefromDatabase(imgtag); }); function uploadIMagetoDatabase(image){ var data, xhr; data = new FormData(); data.append('imageProfile', image); xhr = new XMLHttpRequest(); xhr.open('POST', 'http://localhost:3000/upload', true); xhr.onreadystatechange = function (response) { // document.getElementById("result").innerHTML = xhr.responseText }; xhr.send(data); }
2. 后端上传接口(Express.js)
router.post('/upload', upload.single('imageProfile'),function(req,res){ const imageProfile = req.file; var image=imageProfile; var sql='Insert into Uploads (id,image) VALUES("2",cast("'+image+'" AS BINARY));'; connection.query(sql, function (err, data) { if (err) { console.log("database error-----------"+err); } else { console.log("database insert sucessfull-----------"); } }); });
3. 后端图片获取接口(Express.js)
router.get('/getimage',function(req,res){ var sql = 'SELECT image FROM Uploads'; connection.query(sql, function (err, data) { if (err) { console.log("database error-----------"+err); } else { console.log("database select sucessfull-----------"+data.length); res.json({'image':data[0].image}); } }); });
4. 前端图片展示逻辑(index.html)
function getIMagefromDatabase(imgtag){ $.get("http://localhost:3000/getimage",function(data,status){ console.log("data---"+JSON.stringify(data)); let url = URL.createObjectURL( new Blob([data["image"]], { type: 'image/jpeg' }) ) imgtag.src=url; }); }
异常现象
- 上传后控制台提示数据库插入成功,但接口返回的图片数据是:
{"image":{"type":"Buffer","data": [91,111,98,106,101,99,116,32,79,98,106,101,99,116,93]}},这个data数组对应字符串[object Object]的ASCII码,显然不是图片二进制内容 - 前端生成Object URL后,img标签无法渲染出图片
问题根源与修复方案
1. 核心问题:上传时未存入正确的图片二进制数据
当前上传代码直接将req.file(一个对象)拼接到SQL中,实际存入数据库的是字符串[object Object]的二进制形式,而非图片本身的内容。同时字符串拼接SQL存在注入风险。
修复后的上传接口:
router.post('/upload', upload.single('imageProfile'), function(req, res) { const imageProfile = req.file; if (!imageProfile) { return res.status(400).send('No image uploaded'); } // 使用参数化查询,传入图片的原始二进制buffer const sql = 'INSERT INTO Uploads (id, image) VALUES (?, ?)'; connection.query(sql, ["2", imageProfile.buffer], function(err, data) { if (err) { console.log("database error-----------" + err); res.status(500).send('Database error'); } else { console.log("database insert successful-----------"); res.send('Upload successful'); } }); });
- 用
imageProfile.buffer获取图片的真实二进制内容 - 使用参数化查询(
?占位符),让MySQL驱动自动处理二进制数据的正确存储,同时避免SQL注入
2. 优化图片获取逻辑:直接返回二进制数据
返回JSON格式的Buffer对象会增加前端处理成本,更合理的方式是直接返回图片二进制数据并设置正确的响应头:
修复后的获取接口:
router.get('/getimage', function(req, res) { // 建议指定id查询,避免返回多条数据 const sql = 'SELECT image FROM Uploads WHERE id = ?'; connection.query(sql, ["2"], function(err, data) { if (err) { console.log("database error-----------" + err); res.status(500).send('Database error'); } else { if (data.length === 0) { return res.status(404).send('Image not found'); } console.log("database select successful-----------"); // 假设存储的是jpeg格式,若需要适配多格式,可在上传时将imageProfile.mimetype存入数据库 res.setHeader('Content-Type', 'image/jpeg'); // 直接发送图片二进制数据 res.send(data[0].image); } }); });
简化后的前端展示逻辑:
function getIMagefromDatabase(imgtag) { // 直接将接口地址设为img的src,无需额外处理 imgtag.src = 'http://localhost:3000/getimage'; }
3. 备选方案:通过Base64传输二进制数据(不推荐)
如果必须用JSON返回,可将二进制转成Base64字符串:
后端修改:
router.get('/getimage', function(req, res) { const sql = 'SELECT image FROM Uploads WHERE id = ?'; connection.query(sql, ["2"], function(err, data) { if (err) { console.log("database error-----------" + err); res.status(500).send('Database error'); } else { if (data.length === 0) { return res.status(404).send('Image not found'); } // 将Buffer转成Base64字符串 const imageBase64 = data[0].image.toString('base64'); res.json({ image: imageBase64, mimeType: 'image/jpeg' }); } }); });
前端修改:
function getIMagefromDatabase(imgtag) { $.get("http://localhost:3000/getimage", function(data, status) { // 将Base64转回Blob并生成Object URL const byteCharacters = atob(data.image); const byteNumbers = Array.from(byteCharacters, c => c.charCodeAt(0)); const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: data.mimeType }); const url = URL.createObjectURL(blob); imgtag.src = url; }); }
内容来源于stack exchange
相关产品推荐
相关产品推荐

