信息爆炸的时代,获取到信息的门槛大大降低,但同时也加大了我们理解信息的难度。针对某一个问题,网上会有关于这个问题的好多篇博客或文章。但是翻过一遍后会发现,这些文章中去掉全文都是代码、什么解释也没有的,复制粘贴的,使用各种不必要的框架解决问题的,描述逻辑混乱的,再去掉排版不好看着不舒服的,之后也没几篇能看的了。每个人似乎都在想要提供一个解决方案,但是描述问题的时候能否按逻辑来,一步步走,代码加点注释啥的。我自己写东西或者解决问题的时候喜欢先理清需求,划分步骤,然后一步一步来。比如说,NodeJs 如何实现上传图片到服务器。

1. 任务需求

很常见的一个场景。用户注册页面更换头像后,将图片上传到服务器存储并返回图片在服务器的地址。这里需要注意的一个问题是因为要获取服务器返回的图片地址,所以要异步提交表单。

2. 步骤划分

  • 前端js 代码中判断表单中的图片发生变化时,异步提交表单。
  • 服务器端js 接收到请求,存储图片并返回图片url。
  • 前端js 处理返回请求获取图片url。

3. 代码实现

3.1 前端html 

<img class="photo photo-img" src="">

<form id="img_form" action="" method="POST" enctype="multipart/form-data">

<input name="img" type="file" id="img-input" οnchange="changeImg()" style="display: none"/>

</form>
 

3.2 前端js

因为异步提交表单要用到form.ajaxSubmit,所以需要在html 的头文件中引入jquery.form.js,下载地址:

http://malsup.github.io/jquery.form.js

function changeImg() {

// 图片更改后异步提交表单上传服务器,返回url

var form = $("#img_form");

var options = {

url: domain + '/upload/img', //上传文件的路径

type:'post',

success:function(data){

data = JSON.parse(data);

if(data.code == 0) {

imgUrl = data.data.url;

} else {

alert('上传图片出错!');

}

}

};

form.ajaxSubmit(options);



// 在前端显示上传的图片

var file = $('.photo').find('input')[0].files[0];

var reader = new FileReader();

reader.onload = function(e){

var imgFile = e.target.result;

$('.photo-img').attr('src',imgFile);

$('.photo-img').attr('style','display:block');

}

reader.readAsDataURL(file);

}

3.3 后端js

文件上传需要用到multer 包,所以需要在app.js 中引入,app.js 写法:

"use strict"



var express = require('express');

var multer = require("multer");

var app = express();

var bodyParse = require('body-parser');



// 设置图片存储路径

var storage = multer.diskStorage({

destination: function(req, file, cb) {

cb(null, './uploads');

},

filename: function(req, file, cb) {

cb(null, `${Date.now()}-${file.originalname}`)

}

})



// 添加配置文件到muler对象。

var upload = multer({ storage: storage });

var imgBaseUrl = '../'



// bodyParse 用来解析post数据

app.use(bodyParse.urlencoded({extended:false}));

app.use(express.static('public'));



// 解决跨域问题

app.all('*',function (req, res, next) {

res.header('Access-Control-Allow-Origin', '*');

res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');

res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');



if (req.method == 'OPTIONS') {

res.send(200); /让options请求快速返回/

}

else {

next();

}

});



// 文件上传请求处理,upload.array 支持多文件上传,第二个参数是上传文件数目

app.post('/upload/img', upload.array('img', 2), function (req, res) {

// 读取上传的图片信息

var files = req.files;



// 设置返回结果

var result = {};

if(!files[0]) {

result.code = 1;

result.errMsg = '上传失败';

} else {

result.code = 0;

result.data = {

url: files[0].path

}

result.errMsg = '上传成功';

}

res.end(JSON.stringify(result));

});



// 监听3000端口

var server=app.listen(3000, '0.0.0.0', function () {

console.log('listening at =====> http://0.0.0.0:3000......');

}) ;
 

 

学完还想练练?点这里