最近遇到这么一个需求(也就是题目所示),简单记录一下吧
现在来详细介绍一下要实现怎么样的一个需求,前端上传一张图片,后端获取到并存储在某个文件夹中,前端则能通过 http://127.0.0.1:3000/images/1632830606327.jpg (例子)来获取到后端的那张图片
具体效果如下:
我们用原生JS + 原生node 来实现这一需求
前端
先简单写个上传图片的demo
<input type="file" id="abc" accept="image/jpeg,image/jpg,image/png">
<button onclick="submited()">上传</button>
<br/>
<img src="" alt="" id="showImg" width="350"> //用于图片展示
这一步操作咱们就不做过多解释了,直接进入下一步,之后可想而知获取到上传的图片信息,这里通过文件读取器FileReader来读取文件,将其转化为base64格式(关于FileReader可以参考这一篇文章 FileReader API)
let file = document.getElementById('abc').files[0];
let showImg = document.getElementById('showImg')
let reader = new FileReader();
if (file) {
reader.readAsDataURL(file);
reader.onload = function () {
console.log(reader.result); //返回的是转成base64格式后的图片
}
}
处理完基本数据之后就是发起接口请求了
function submited() {//button上面的那个方法
let file = document.getElementById('abc').files[0];
let showImg = document.getElementById('showImg')
let reader = new FileReader();
if (file) {
reader.readAsDataURL(file);
reader.onload = function () {
// console.log(reader.result);
//新加入的代码 发起接口请求
let baseImg = reader.result.replace(/^data:image\/\w+;base64,/,"");//去除掉前面的前缀
let xhr = new XMLHttpRequest();//原生js发起接口请求
xhr.open('post', 'http://127.0.0.1:3000/showImg');//用post发起请求
xhr.send(baseImg);//将数据也传给后端
xhr.onreadystatechange = function () {//注册事件
if (xhr.readyState == 4 && xhr.status == 200) {
//showImg.src = xhr.responseText; //将处理好的url赋值给img标签的src在页面展示
}
}
}
}
}
前端基本到这就结束了,总结一下前端干了些啥:通过FileReader获取本地上传的图片,然后通过readAsDataURL(blob)方法将图片转化成base64格式,最后用原生JS发起接口请求
后端
接下来我们来处理后端的一些逻辑:通过http去启动一个3000端口的服务,再运用Buffer(关于Buffer)去解析处理前端传过来的图片信息,之后通过node含有的fs模块去解析下载通过Buffer处理后的数据(返回的一个Buffer实例)
先启动一个3000端口的服务
let http = require('http');
let server = http.createServer((req, res) => {
});
server.listen(3000, () => {
console.log('服务已启动');
})
然后再到createServer中去做之后的逻辑操作,前端后端启动的端口不一样,会产生跨域
res.writeHead(200, {
'Content-Type': 'text/plain',//设置请求头类型
"Access-Control-Allow-Origin": "*"//*表示允许所有的域来请求 简单粗暴一点 实际操作不能这么操作
})
前端发起的是对 /showImg 接口进行请求,而且我们发起的是post请求
if (req.url == '/showImg' && req.method == 'POST') {
let data = '';//存储前端传过来的数据
req.on('data', cur => {
data += cur;//post请求,数据会分段传输
})
req.on('end', () => {//数据接收完毕后调用
//setPic(data,res); 这是后面的数据解析操作
})
}
后端的文件格式如下
我们将传过来的数据转化后下载到images中
function setPic(data,res) {
const path_1 = './images/' + Date.now() + '.jpg';//通过时间戳给图片重命名
const picture = path_1.replace(/\./, 'http://127.0.0.1:3000');//这是返回给前端的信息
const dataBuffer = Buffer.from(data, 'base64');//返回一个初始化的新的 Buffer 实例
fs.writeFile(path_1, dataBuffer, function (err) {//下载图片到images文件中
if (err) {
res.end(err)
}
});
res.end(picture);
}
一些基本的逻辑就差不多实现了,前端传图片,后端获取重命名并下载。之后就是我们的关键步骤,我是这么干的,当识别到有接口请求时,就调用该函数去匹配url,如果url中含有存储图片的文件名则继续执行
server.on('request',(req,res)=>{
if(req.url.match(/\/images/)){//相当于将images文件暴露出来
fs.readFile('.' + req.url,(err,data)=>{
if(err){
console.log(err);
}else{
res.end(data);
}
})
}
})
至此已经完成了所有逻辑,现在可以通过http://127.0.0.1:3000/images/图片名 来访问图片
写在后面
这里是对于原生node而言,而对于express及koa就更方便了,只需要设置一个静态文件管理就行了
express
const path = require('path')
const express = require('express');
app.use('/images',express.static(path.join(__dirname, 'images')));;//自带 托管静态文件
app.listen(3000,() => {
console.log('服务已启动');
})
koa
通过 npm i koa-static 或者 yarn add koa-static 安装这个插件
const Koa = require('koa')
const app = new Koa()
app.use(require('koa-static')(__dirname + '/images'))//托管静态文件
在我看来这三种其实都差不多,都是通过将静态文件夹暴露出来,供访问。