上QQ阅读APP看书,第一时间看更新
2.7 文件上传
文件的上传和下载在实际应用场景中会经常遇到,2.6节介绍过如何获取post请求的数据,文件上传也是通过post请求实现的,那么可以直接通过ctx.request.body获取文件内容吗?答案是不可以,文件上传需要通过另外一个中间件koa-body来实现,文件下载可以通过koa-send中间件来实现。本节带领读者使用这两个中间件。
首先,文件上传需要先在前端实现一个上传文件的标签和点击按钮,然后利用FormData对象进行封装,最后通过XMLHttp-Request对象发送。具体页面代码如下。
<!-- static/upload.html --> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>上传</title> </head> <body> <input type="file" /> <button>点击上传</button> </body> <script> document.querySelector('button').onclick = function () { // 这里会获取一个files数组对象, 因为是单文件上传, 所以获取第一 个即可 let file = document.querySelector('input').files[0]; let xhr = new XMLHttpRequest(); xhr.open('post', '/upload', true); xhr.onload = function () { let res = JSON.parse(xhr.responseText); console.log(res); } let form = new FormData(); form.append('file', file); // 对应key value xhr.send(form); } </script> </html>
在页面上的呈现效果如图2-16所示。
图2-16 上传页面效果图
经过前面几节的学习,读者应该学会了静态服务器以及路由的使用,文件上传用到的中间件是koa-body,需要读者自行安装,其他的中间件都是之前介绍过的,不再赘述,下面是Koa上传文件的实现逻辑。
// app.js const Koa = require('koa') const path = require('path') const fs = require('fs') const static = require('koa-static') const Router = require('koa-router') const koaBody = require('koa-body'); const app = new Koa() const router = new Router() const staticPath = './static' app.use(koaBody({ multipart: true, formidable: { maxFileSize: 200*1024*1024 // 设置上传文件的限制, 默认2MB } })); app.use(static( path.join( __dirname, staticPath) )) app.use(router.routes()) router.post('/upload', async ( ctx ) => { // 获取文件对象 const file = ctx.request.files.file // 读取文件内容 const data = fs.readFileSync(file.path); // 保存到服务端 fs.writeFileSync(path.join(__dirname, file.name), data); ctx.body = { message: '上传成功!' }; }) app.listen(4000, () => { console.log('server is running, port is 4000') })
至此,简单的文件上传功能就实现了,读者可以自己运行一下。上传后的文件将保存在app.js同级目录下。
接下来实现下载的功能,对于前端来说,下载可以通过window.open来实现,代码如下。
<!-- download.html --> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>下载</title> </head> <body> <button onclick="handleClick()">立即下载</button> </body> <script> const handleClick = () => { window.open('/download/1.png'); } </script> </html>
假设在之前上传了图片1.png到服务端,现在要将其下载到客户端,在Koa中是如何实现的呢?下载需要安装一个中间件koa-send,那么在app.js文件中增加下载的逻辑,代码如下。
// app.js const send = require('koa-send'); router.get('/download/:name', async (ctx) => { const name = ctx.params.name; const path = `${name}`; ctx.attachment(path); await send(ctx, path); })
整体思路就是前端点击下载,调用Koa中对应的路由,将文件回传到浏览器。下载的效果如图2-17所示。
图2-17 文件下载效果