Node.js 上传图片

2016年7月8日

代码地址

前端开发环境运行起来

npm install
npm start

访问 localhost:3000 页面可以看到一张图片和一个可以更改图片的按钮。

前端代码分析

实现图片上传功能,需要一个类型为 fileinput 输入框,添加这个输入框:

<input type='file' id='avatarInput' onChange={this.handleChange.bind(this)} />

同时,还给这个输入框添加了一个 onChange 属性,当上传文件的时候会触发 onChange 属性对应的事件处理程序 handleChange

handleChange(e) {
  e.preventDefault();
  let API_URL = 'http://localhost:8000';
  let file= e.target.files[0];
  let formData = new FormData();
  formData.append('avatar', file);

  axios.post(`${API_URL}/upload`, formData)
  .then( response => {
    this.setState({imageURL: API_URL + response.data.path.substr(6)});
  });
}

这里没有构建 form 表单来上传文件,而是通过 FormData 对象 来模拟一个表单。然后借助 axios 向服务器的 http://localhost:8000/upload 接口发送 post 请求,把构建的 formData 表单数据传送给服务器,若请求成功则设置 state 变量 imageURL 的状态值为所上传的图片在服务器上的链接地址,

this.setState({imageURL: API_URL + response.data.path.substr(6)});

从而导致组件重新渲染,原来显示的静态图片就被新上传的图片替换了,不过代码中没有存储新上传图片的链接地址,刷新页面页面中显示的图片又会恢复原貌。

后端开发环境运行起来

npm install -g nodemon
npm install
nodemon app.js

后端代码分析

首先看一下 package.json 文件,除了 express 之外,只用到了两个 npm 包:body-parsermulter。其中 body-parser 是一个 request body 解析器,用到了它提供的两个功能模块:

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

不过它不能处理 multipart 类型的 body,所以需要一个专门用来解决文件上传问题的 node.js 中间件 multer。

使用 multer 中间件

var multer = require('multer');
var upload = multer({ dest: './public/avatars/' })

通过上面语句可以设置上传文件的存储路径,项目根目录下的 public/avatars 目录中。然后定义文件上传的接口:

app.post("/upload", upload.single('avatar'), function(req, res) {
  console.log(req);
  res.send(req.file);
});

因为只是上传一张图片,所以用到了 multer 的 single 接口, 其参数 avatar 字符串对应客户端表单对象 formData 中包含的 avatar 字段,这两个值必须保持一致。当客户端请求 /upload 接口的时候,multer 会给 request 对象中添加一个 file 对象属性,其包含的信息如下:

file:
 { fieldname: 'avatar',
   originalname: 'xxx.png',
   encoding: '7bit',
   mimetype: 'image/png',
   destination: './public/avatars/',
   filename: 'ef3db8be4611b587b47f09d64255f23f',
   path: 'public/avatars/ef3db8be4611b587b47f09d64255f23f',
   size: 16937 } }

然后我们可以通过 res.send(req.file) 语句把获取的上传文件的信息发送到客户端,从而客户端就能得到上传文件在服务器上的存储位置。

展示上传的图片

虽然图片已经上传成功了,也知道了图片详细的链接地址,但是图片还不能在客户端显示出来。我们还需要做些工作,添加一行代码:

app.use(express.static(path.join(__dirname, 'public')));

通过 express 提供的 static 接口,让储存在 public 目录下的静态文件供外界使用,然后在客户端代码中通过

<img src='http://localhost:8000/avatars/xxxx' />

就能让上传到服务器上的图片在浏览器中显示出来了。