Deno Oak中显示Blob图片报错:Not allowed to load local resource
错误原因与解决方案
错误根源
你在后端(Deno Oak)调用的URL.createObjectURL是服务器端运行时的API,生成的Blob URL格式类似blob:file:///xxxxxx,仅在服务器进程内部有效。浏览器会将其识别为服务器本地资源,出于同源策略和安全限制,禁止前端加载这类跨上下文的资源,因此抛出「Not allowed to load local resource」错误。
注意:浏览器端的URL.createObjectURL才是生成浏览器可识别的临时Blob URL的正确方式,两者运行在完全不同的上下文,不能混用。
临时解决:上传后直接显示图片
若仅需实现上传后即时显示,可修改后端将图片转为Base64编码返回给前端:
后端修改代码
const uploadFiles = async(ctx:any)=>{ const body = await ctx.request.body({type: 'form-data'}); const product = await body.value.read({maxSize: 500000000 }); if(!ctx.request.hasBody){ ctx.response.status = 400; ctx.response.body ={ success: false, msg: 'No data' } }else{ try { const file = product.files[0].content; // 将二进制文件转为Base64编码 const base64 = btoa(new Uint8Array(file).reduce((data, byte) => data + String.fromCharCode(byte), '')); const imgUrl = `data:image/jpeg;base64,${base64}`; ctx.render('./fu.ejs',{upload:true, urlData: imgUrl}); } catch (err) { ctx.response.status = 200; ctx.response.body = { success: false, msg: err.toString() } } } }
前端无需修改,直接使用返回的urlData作为img.src即可,Data URI是浏览器可直接识别的资源格式。
完整流程:存入数据库+读取显示
1. 上传时将图片存入数据库
推荐在数据库中存储图片的二进制数据(Blob类型字段,比Base64更节省空间),示例伪代码:
const uploadFiles = async(ctx:any)=>{ const body = await ctx.request.body({type: 'form-data'}); const product = await body.value.read({maxSize: 500000000 }); if(!ctx.request.hasBody){ ctx.response.status = 400; ctx.response.body ={ success: false, msg: 'No data' } }else{ try { const file = product.files[0].content; const mimeType = product.files[0].type || 'image/jpeg'; // 将二进制数据存入数据库(以PostgreSQL为例) await db.query(`INSERT INTO images (data, mime_type) VALUES ($1, $2)`, [file, mimeType]); const imageId = // 获取刚插入的图片ID ctx.render('./fu.ejs',{upload:true, imageId: imageId}); } catch (err) { ctx.response.status = 200; ctx.response.body = { success: false, msg: err.toString() } } } }
2. 新增图片读取接口
后端注册接口,根据图片ID从数据库取出二进制数据并返回:
const getImage = async(ctx:any)=>{ const imageId = ctx.params.id; // 从数据库查询图片数据与MIME类型 const result = await db.query(`SELECT data, mime_type FROM images WHERE id = $1`, [imageId]); if(!result.rows.length){ ctx.response.status = 404; ctx.response.body = 'Image not found'; return; } const { data, mime_type } = result.rows[0]; // 设置响应头 ctx.response.headers.set('Content-Type', mime_type); // 返回二进制图片数据 ctx.response.body = data; } // 路由注册示例 router.get('/images/:id', getImage);
3. 前端读取显示
前端直接使用接口地址作为图片源:
const etat = $('#etat').html(); const photoDiv = $('.photoDiv'); const imageId = $('#imageId').text(); // 从模板获取图片ID if(etat === 'true'){ const img = document.createElement("img"); img.src = `/images/${imageId}`; // 接口地址 img.height = 200; img.width = 200; photoDiv.append(img); }
内容的提问来源于stack exchange,提问作者Kogami997
相关产品推荐
相关产品推荐

