也是在最近一点时间写小demo 遇到的一些问题
比如在用户界面,用户选择本地的一张照片,前端把照片传到后端,后端怎么把照片保存到服务器,然后返回给 图片线上地址。也是找了一些文章,然后分享下。
技术
前端:react
后端:egg.js(node框架)
base64 转换
转二进制 保存图片
base64(mdn)
Base64 是一组相似的二进制到文本(binary-to-text)的编码规则,使得二进制数据在解释成 radix-64 的表现形式后能够用 ASCII 字符串的格式表示出来。Base64 这个词出自一种 MIME 数据传输编码。
Base64 编码普遍应用于需要通过被设计为处理文本数据的媒介上储存和传输二进制数据而需要编码该二进制数据的场景。这样是为了保证数据的完整并且不用在传输过程中修改这些数据。Base64 也被一些应用(包括使用 MIME 的电子邮件)和在 XML 中储存复杂数据时使用。
为什么转成base64&好处
- 传输信道只支持ASCII字符,不方便传输二进制流的场合。含有非ASCII字符,容易出现编码问题。所以需要用base64转化为ascii字符。Base64用于将二进制数据编码成ASCII字符 (图片、文件等都可转化为二进制数据)。
- 图片的 base64 编码就是可以将一副图片数据编码成一串字符串,使用该字符串代替图像地址。
- 将图片转换为base64编码最常见的应用就是在将网页中的一些图片转为base64编码可以实现网页图片在网速 不好的时候先于内容加载和减少http的请求次数来减少网站服务器的负担。
获取文件的base64格式
<!-- 我这里写个简单的样式 -->
<input type="file">
<button>提交</button>
选择一张图片文件,然后点击提交按钮我们就会得到一个 base64字符串
const files = document.querySelector('input[type=file]')
const btn = document.querySelector('button')
btn.addEventListener('click', function () {
var reader = new FileReader();
reader.readAsDataURL(files.files[0]);
reader.onloadend = function () {
var base64 = reader.result;
console.log(base64);
}
})
console:
我们可以通过这个 base64 格式的字符串,直接复制到浏览器的地址上,就能访问图片
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAADMUExURUdwTPn5+/j4/Pn5+/n5/Pn5+/n5+/n5+/j4+/n5+vv7+/j4+/n5+vv7+/n5+/j4+/j4+vn5+vn5/Pj4+/r6+vr6/Pn5+/n5+/r6+vr6/Pn5+/j4+vj4+gAAAPHx8wcHB0ZGRkdHSLS0trOztbKytLGxs2NjZAYGBkxMTfPz9dHR0pCQkggICPb2+F5eX2JiYxoaGkZGR4+PkdLS093d38jIyQkJCUtLTDc3N7W1t9PT1I2Nj2LkZLoAAAAkdFJOUwD+IpKwVQT57P1y0kIM58w8BvB03wjRW7kzYoka7wJtZbFuA8zxGUAAAAIESURBVFjDrZjpdoIwEIWjoIC7goJQ1w7a1ta6dt/7/u/UKNrWhWSCc/8y5ztAMncWxuLVbvqB3nBMwzCdhh74zTZLoLOO3oI9tfTOmRql7noWHJXluXU0pmiXQKCSXURhsjkTJDJzWTmnkgeE8hUJpqqlAKWUVhVx0mVAq5yO5xRqoKBaIY6TMUBJRuY4p2uBoqzu0fdR5nDSkXcqGJBAxsF/StcgkWp7Z1ctQ0KVd++TBoml7eRFKjko9S9bsnk4Qfm/DM7BScr9+o95Gsjc+pMNJ8re+KrID19eB3JQKXJfNz5ieReGD59ykrsGefEB85BrOJKCvHXdESTrJMSRrFWV6gsCxiGS1OGgnuD582JDupKAdF6XW6KA0RBHarVZUxxxjSQ1mQ8kJJ8FQEIKmA4kJJ015Pf25lZOajAH8KTFLDbEYSgL2ZLu462EoarQ4CMCvcfXJRRocBlxwm8ByFTgXEwFn+YocAQe58iPH8Xhx6+TcPiFDEg4PEV8Eg5PWqGNTLEcbiNCY5tjOdzYhFY7QXJWVoswfzlnbf6icjR745xHOWddjkQFEr7Gk6elPIk8WcnGypU3EShtmgiytoau0SJr/eiaUbL2mK5hpxshyIYaujGLbvCjG0XphmO6cZ1ugUC30qBbshCufegWUYSrsWhZ1+8dLut6qsu6SOcq68Mf88U7H+osen4AAAAASUVORK5CYII=
这串字符串其实就是一张照片的DataURL,就是利用base64编码把图片数据翻译成标准ASCII字符。也可以把这个字符串直接放到 img 标签 src 上。这样也可以节省 http网络的一次请求
字符串的结构:
data:image/png;base64 声明数据协议及类型名称
base64 编码形式为base64
iVBORw0KGgoAAAA... 内容
接下来我们开始完整的演示文件上传的过程
前端: react(就是转base64,上面已经讲到)
后端:egg.js(node)
前端
很简单的样式,我这里做了一个回显的效果就是获取完 图片的 base64 字符串然后 在赋值给img
//react
const fileRef = useRef(0)
const [ src, setSrc] = useState()
<img src={src} alt=""/>
<input type="file" name="" id="" ref={fileRef} onChange={(e) => fileBtn(e)}/>
函数 filebtn
function fileBtn(e){
var imgfile = e.target.files[0] //获取文件信息
var reader = new FileReader();
reader.onload=function(){
var fileurl = reader.result
setSrc(fileurl) // 这个 useState 把获取的base64 给到img 的src 上
// 这里有一个向后端发送的请求
postimg({
files: fileurl
}).then(res=>{
console.log(res);
})
}
reader.readAsDataURL(imgfile)
}
postimg 这里是封装的一个请求 http 是一个 axios(网上封装好的)(请求需要用 post)
function postimg(params){
return new Promise((resolve,reject)=>{
http('post','postimg',params).then(res=>{
resolve(res)
},error =>{
console.log("网络异常~", error);
reject(error)
})
})
}
到这里前端部分就已经实现完毕了
后端
首先在router 文件里编写路由
router.post('/postimg', controller.home.postimg);
然后在controller 文件下 home 文件 里面的 postimg(这里强调下要用post 请求)
我们这里是用了一个中间件(方便我们获取 参数,不需要考虑 get 或者是 post)
params(key) {
const method = this.request.method;
if (method === 'GET') {
return key ? this.query[key] : this.query;
}
return key ? this.request.body[key] : this.request.body;
},
async postimg() {
const { ctx } = this;
const file = ctx.params().files; // 获取参数
const imgtype = file.match(/data:image\/(png|jpep|jpg|JPG|gif|webp);/)[1];//获取文件的类型
const filename = `${Math.floor(Math.random() * 10000000000)}.${imgtype}`;//获取随机数
const publi = `//${ctx.request.header.host}/public/updataImg/${filename}`; //返回的 文件路径
const filepath = path.join(`${__dirname}/../public`, `updataImg/${filename}`);//写入文件的路径
const fileBuffer = Buffer.from(file.replace(/^data:image\/(png|jpep|jpg|gif|webp);base64,/, ''), 'base64'); //讲base64 的 data:image/png;base64 去掉,并转成而二进制
console.log(publi, 123);
fs.writeFileSync(filepath, fileBuffer); //写入文件
}
我这是用 egg 来写的,如果用express或者koa 搭建的服务器,原理也是一样,复制粘贴即可。