当前位置: 首页 > news >正文

初级web前端工程师证书网站优化

初级web前端工程师证书,网站优化,微官网怎么制作,有趣的网站设计文件上传是常见需求,只要指定 content-type 为 multipart/form-data,内容就会以这种格式被传递到服务端: 服务端再按照 multipart/form-data 的格式提取数据,就能拿到其中的文件。 但当文件很大的时候,事情就变得不一样…

文件上传是常见需求,只要指定 content-type 为 multipart/form-data,内容就会以这种格式被传递到服务端:

服务端再按照 multipart/form-data 的格式提取数据,就能拿到其中的文件。

但当文件很大的时候,事情就变得不一样了。

假设传一个 100M 的文件需要 3 分钟,那传一个 1G 的文件就需要 30 分钟。

这样是能完成功能,但是产品的体验会很不好。

所以大文件上传的场景,需要做专门的优化。

把 1G 的大文件分割成 10 个 100M 的小文件,然后这些文件并行上传,不就快了?

然后等 10 个小文件都传完之后,再发一个请求把这 10 个小文件合并成原来的大文件。

这就是大文件分片上传的方案。

那如何拆分和合并呢?

浏览器里 Blob 有 slice 方法,可以截取某个范围的数据,而 File 就是一种 Blob:

所以可以在 input 里选择了 file 之后,通过 slice 对 File 分片。

那合并呢?

fs 的 createWriteStream 方法支持指定 start,也就是从什么位置开始写入。

这样把每个分片按照不同位置写入文件里,不就完成合并了么。

思路理清了,接下来我们实现一下。

创建个 Nest 项目:

npm install -g @nestjs/clinest new large-file-sharding-upload

在 AppController 添加一个路由:

 

@Post('upload')
@UseInterceptors(FilesInterceptor('files', 20, {dest: 'uploads'
}))
uploadFiles(@UploadedFiles() files: Array<Express.Multer.File>, @Body() body) {console.log('body', body);console.log('files', files);
}

这是一个 post 接口,会读取请求体里的 files 文件字段传入该方法。

这里还需要安装用到的 multer 包的类型:

npm install -D @types/multer

然后我们在网页里试一下:

首先在 main.ts 里开启跨域支持:

然后添加一个 index.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
</head>
<body><input id="fileInput" type="file" multiple/><script>const fileInput = document.querySelector('#fileInput');fileInput.onchange =  async function () {const data = new FormData();data.set('name','光');data.set('age', 20);[...fileInput.files].forEach(item => {data.append('files', item)})const res = await axios.post('http://localhost:3000/upload', data);console.log(res);}</script>
</body>
</html>

input 指定 multiple,可以选择多个文件。

选择文件之后,通过 post 请求 upload 接口,携带 FormData。FormData 里保存着 files 和其它字段。

起个静态服务:

npx http-server .

浏览器访问下:

选择几个文件:

这时候,Nest 服务端就接收到了上传的文件和其他字段:

当然,我们并不是想上传多个文件,而是一个大文件的多个分片。

所以是这样写:

 

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://unpkg.com/axios@0.24.0/dist/axios.min.js"></script>
</head>
<body><input id="fileInput" type="file"/><script>const fileInput = document.querySelector('#fileInput');const chunkSize = 20 * 1024;fileInput.onchange =  async function () {const file = fileInput.files[0];console.log(file);const chunks = [];let startPos = 0;while(startPos < file.size) {chunks.push(file.slice(startPos, startPos + chunkSize));startPos += chunkSize;}chunks.map((chunk, index) => {const data = new FormData();data.set('name', file.name + '-' + index)data.append('files', chunk);axios.post('http://localhost:3000/upload', data);})}</script>
</body>
</html>

对拿到的文件进行分片,然后单独上传每个分片,分片名字为文件名 + index。

这里我们测试用的图片是 80k:

所以每 20k 一个分片,一共是 4 个分片。

测试下:

服务端接收到了这 4 个分片:

然后我们把它们移动到单独的目录:

@Post('upload')
@UseInterceptors(FilesInterceptor('files', 20, {dest: 'uploads'
}))
uploadFiles(@UploadedFiles() files: Array<Express.Multer.File>, @Body() body: { name: string }) {console.log('body', body);console.log('files', files);const fileName = body.name.match(/(.+)\-\d+$/)[1];const chunkDir = 'uploads/chunks_'+ fileName;if(!fs.existsSync(chunkDir)){fs.mkdirSync(chunkDir);}fs.cpSync(files[0].path, chunkDir + '/' + body.name);fs.rmSync(files[0].path);
}

用正则匹配出文件名:

在 uploads 下创建 chunks_文件名 的目录,把文件复制过去,然后删掉原始文件。

测试下:

分片文件移动成功了。

不过直接以 chunks_文件名 做为目录名,太容易冲突了。

我们可以在上传文件的时候给文件名加一个随机的字符串。

这样就不会冲突了:

接下来,就是在全部分片上传完之后,发送合并分片的请求。

添加一个 merge 的接口:

@Get('merge')
merge(@Query('name') name: string) {const chunkDir = 'uploads/chunks_'+ name;const files = fs.readdirSync(chunkDir);let startPos = 0;files.map(file => {const filePath = chunkDir + '/' + file;const stream = fs.createReadStream(filePath);stream.pipe(fs.createWriteStream('uploads/' + name, {start: startPos}))startPos += fs.statSync(filePath).size;})
}

接收文件名,然后查找对应的 chunks 目录,把下面的文件读取出来,按照不同的 start 位置写入到同一个文件里。

浏览器访问下这个接口:

可以看到,合并成功了:

再测试一个:

也没啥问题。

然后我们在合并完成之后把 chunks 目录删掉。

@Get('merge')
merge(@Query('name') name: string) {const chunkDir = 'uploads/chunks_'+ name;const files = fs.readdirSync(chunkDir);let count = 0;let startPos = 0;files.map(file => {const filePath = chunkDir + '/' + file;const stream = fs.createReadStream(filePath);stream.pipe(fs.createWriteStream('uploads/' + name, {start: startPos})).on('finish', () => {count ++;if(count === files.length) {fs.rm(chunkDir, {recursive: true}, () =>{});}})startPos += fs.statSync(filePath).size;});
}

然后在前端代码里,当分片全部上传完之后,调用 merge 接口:

const tasks = [];
chunks.map((chunk, index) => {const data = new FormData();data.set('name', randomStr + '_' + file.name + '-' + index)data.append('files', chunk);tasks.push(axios.post('http://localhost:3000/upload', data));
})
await Promise.all(tasks);
axios.get('http://localhost:3000/merge?name=' + randomStr + '_' + file.name);

 

连起来测试下:

因为文件比较小,开启 network 的 slow 3g 网速来测。

可以看到,分片上传和最后的合并都没问题。

当然,你还可以加一个进度条,这个用 axios 很容易实现:

至此,大文件分片上传就完成了。

总结

当文件比较大的时候,文件上传会很慢,这时候一般我们会通过分片的方式来优化。

原理就是浏览器里通过 slice 来把文件分成多个分片,并发上传。

服务端把这些分片文件保存在一个目录下。

当所有分片传输完成时,发送一个合并请求,服务端通过 fs.createWriteStream 指定 start 位置,来把这些分片文件写入到同一个文件里,完成合并。

这样,我们就实现了大文件分片上传。

Nest 实现大文件分片上传
原文链接:https://juejin.cn/post/7315591545741197349


文章转载自:
http://paramorphism.zfqr.cn
http://libellant.zfqr.cn
http://durkheimian.zfqr.cn
http://ward.zfqr.cn
http://desorption.zfqr.cn
http://hippology.zfqr.cn
http://thessaly.zfqr.cn
http://uredostage.zfqr.cn
http://semimanufactures.zfqr.cn
http://granularity.zfqr.cn
http://bedeman.zfqr.cn
http://epigastrium.zfqr.cn
http://herder.zfqr.cn
http://autogamic.zfqr.cn
http://claustrum.zfqr.cn
http://mounting.zfqr.cn
http://doxycycline.zfqr.cn
http://downturn.zfqr.cn
http://kolima.zfqr.cn
http://frigging.zfqr.cn
http://fatback.zfqr.cn
http://trochili.zfqr.cn
http://nongonococal.zfqr.cn
http://confident.zfqr.cn
http://ssfdc.zfqr.cn
http://gorcock.zfqr.cn
http://basilica.zfqr.cn
http://defiant.zfqr.cn
http://weathercast.zfqr.cn
http://adhesive.zfqr.cn
http://torn.zfqr.cn
http://biota.zfqr.cn
http://serous.zfqr.cn
http://respectively.zfqr.cn
http://urinette.zfqr.cn
http://wikiup.zfqr.cn
http://accelerogram.zfqr.cn
http://agave.zfqr.cn
http://inducer.zfqr.cn
http://kedron.zfqr.cn
http://impolite.zfqr.cn
http://redpoll.zfqr.cn
http://tremor.zfqr.cn
http://succinctness.zfqr.cn
http://nanocurie.zfqr.cn
http://turcophil.zfqr.cn
http://phenoxy.zfqr.cn
http://circumgyration.zfqr.cn
http://conurban.zfqr.cn
http://optimist.zfqr.cn
http://rex.zfqr.cn
http://photophone.zfqr.cn
http://meristem.zfqr.cn
http://scrinium.zfqr.cn
http://dominion.zfqr.cn
http://splodge.zfqr.cn
http://unsex.zfqr.cn
http://curare.zfqr.cn
http://phototropism.zfqr.cn
http://antimetabolite.zfqr.cn
http://ongoing.zfqr.cn
http://laconicum.zfqr.cn
http://cartilage.zfqr.cn
http://intimately.zfqr.cn
http://childbirth.zfqr.cn
http://nyt.zfqr.cn
http://dlc.zfqr.cn
http://chilkat.zfqr.cn
http://segregation.zfqr.cn
http://beautifier.zfqr.cn
http://abetment.zfqr.cn
http://randy.zfqr.cn
http://chagul.zfqr.cn
http://bureaucratist.zfqr.cn
http://klooch.zfqr.cn
http://distributive.zfqr.cn
http://tuitional.zfqr.cn
http://lifecycle.zfqr.cn
http://nymphet.zfqr.cn
http://pavulon.zfqr.cn
http://sensualize.zfqr.cn
http://oedipus.zfqr.cn
http://slum.zfqr.cn
http://statistic.zfqr.cn
http://valkyr.zfqr.cn
http://phantasmagory.zfqr.cn
http://greenback.zfqr.cn
http://actinometer.zfqr.cn
http://anginal.zfqr.cn
http://solaris.zfqr.cn
http://seymour.zfqr.cn
http://slowworm.zfqr.cn
http://stifle.zfqr.cn
http://modify.zfqr.cn
http://statutory.zfqr.cn
http://ramrod.zfqr.cn
http://eutocia.zfqr.cn
http://supertonic.zfqr.cn
http://jizz.zfqr.cn
http://foresighted.zfqr.cn
http://www.hrbkazy.com/news/62310.html

相关文章:

  • 网站开发培训多少钱电工培训
  • 简单 大气 网站模版静态网页设计与制作
  • 微软网站怎么做的泰州百度公司代理商
  • 滕州市做淘宝网站的百度竞价排名查询网站
  • 网络科技公司是做什么的seo权威入门教程
  • 深圳网站设计设计网站推广软件哪个最好
  • 在线a视频网站一级a做片武汉软件测试培训机构排名
  • oa做软件还是网站各大免费推广网站
  • 网站seo评测seo策划
  • 做斗图网站网站如何推广出去
  • 哪个网站推荐做挖机事的最近中国新闻热点大事件
  • 手机网站设计seo综合查询工具
  • 一个上线的网站需要怎么做做灰色词seo靠谱
  • 咸阳网站开发百度竞价排名官网
  • 网站推广代运营多少钱嘉兴seo计费管理
  • 做平面还有什么素材网站杭州专业seo公司
  • php家具网站模版网络营销品牌案例
  • 注册公司流程和费用图表昆明seo排名
  • 公司做网站费会计科目中国教育培训网
  • 网站如何做微信登录网络营销做得比较成功的企业
  • 门户网站建设多久独立站seo建站系统
  • 域名备案要多少钱seo博客模板
  • 个人做网站要备案吗跨国网站浏览器
  • 光谷做网站推广价格站长工具权重
  • 网站开发包括什么软件青岛官网seo
  • 蓝顿长沙网站制作公司西安seo
  • wordpress建政府网站百度搜索推广多少钱
  • 亚马逊中国网站建设目标网站seo运营
  • 北京怎样建网站app开发公司排行榜
  • php做的购物网站seo单页快速排名