整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

手把手教你前端的各种文件上传攻略和大文件断点续传



在前面

今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受。这么好的光阴怎么浪费,睡觉、吃饭、打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完。

这篇文章比较基础,在国庆期间的业余时间写的,这几天又完善了下,力求把更多的前端所涉及到的关于文件上传的各种场景和应用都涵盖了,若有疏漏和问题还请留言斧正和补充。

自测读不读

以下是本文所涉及到的知识点,break or continue ?

  • 文件上传原理
  • 最原始的文件上传
  • 使用 koa2 作为服务端写一个文件上传接口
  • 单文件上传和上传进度
  • 多文件上传和上传进度
  • 拖拽上传
  • 剪贴板上传
  • 大文件上传之分片上传
  • 大文件上传之断点续传
  • node 端文件上传

原理概述

原理很简单,就是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。

我们都知道如果要上传一个文件,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法。

那么multipart/form-data表示什么呢?

multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。

multipart/form-data 结构

看下 http 请求的消息体



  • 请求头:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———XXX开始,以———XXX结尾。

  • 消息体- Form Data 部分

每一个表单项又由Content-Type和Content-Disposition组成。

Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。

Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。

解析

客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。

可能大家马上能想到通过正则或者字符串处理分割出内容,不过这样是行不通的,二进制buffer转化为string,对字符串进行截取后,其索引和字符串是不一致的,所以结果就不会正确,除非上传的就是字符串。

不过一般情况下不需要自行解析,目前已经有很成熟的三方库可以使用。

至于如何解析,这个也会占用很大篇幅,后面的文章在详细说。

最原始的文件上传

使用 form 表单上传文件

在 ie时代,如果实现一个无刷新的文件上传那可是费老劲了,大部分都是用 iframe 来实现局部刷新或者使用 flash 插件来搞定,在那个时代 ie 就是最好用的浏览器(别无选择)。

DEMO



这种方式上传文件,不需要 js ,而且没有兼容问题,所有浏览器都支持,就是体验很差,导致页面刷新,页面其他数据丢失。

HTML

 <form method="post" action="http://localhost:8100" enctype="multipart/form-data">

        选择文件:
            <input type="file" name="f1"/> input 必须设置 name 属性,否则数据无法发送<br/>
<br/>
            标题:<input type="text" name="title"/><br/><br/><br/>

        <button type="submit" id="btn-0">上 传</button>

</form>

复制代码

文件上传接口

服务端文件的保存基于现有的库koa-body结合 koa2实现服务端文件的保存和数据的返回。

在项目开发中,文件上传本身和业务无关,代码基本上都可通用。

在这里我们使用koa-body库来实现解析和文件的保存。

koa-body 会自动保存文件到系统临时目录下,也可以指定保存的文件路径。



然后在后续中间件内得到已保存的文件的信息,再做二次处理。

  • ctx.request.files.f1 得到文件信息,f1为input file 标签的 name
  • 获得文件的扩展名,重命名文件

NODE

/**
 * 服务入口
 */
var http = require('http');
var koaStatic = require('koa-static');
var path = require('path');
var koaBody = require('koa-body');//文件保存库
var fs = require('fs');
var Koa = require('koa2');

var app = new Koa();
var port = process.env.PORT || '8100';

var uploadHost= `http://localhost:${port}/uploads/`;

app.use(koaBody({
    formidable: {
        //设置文件的默认保存目录,不设置则保存在系统临时目录下  os
        uploadDir: path.resolve(__dirname, '../static/uploads')
    },
    multipart: true // 开启文件上传,默认是关闭
}));

//开启静态文件访问
app.use(koaStatic(
    path.resolve(__dirname, '../static') 
));

//文件二次处理,修改名称
app.use((ctx) => {
    var file = ctx.request.files.f1;//得道文件对象
    var path = file.path;
    var fname = file.name;//原文件名称
    var nextPath = path+fname;
    if(file.size>0 && path){
        //得到扩展名
        var extArr = fname.split('.');
        var ext = extArr[extArr.length-1];
        var nextPath = path+'.'+ext;
        //重命名文件
        fs.renameSync(path, nextPath);
    }
    //以 json 形式输出上传文件地址
    ctx.body = `{
        "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
    }`;
});

/**
 * http server
 */
var server = http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ......   ');
复制代码

CODE

https://github.com/Bigerfe/fe-learn-code/

ess和Sass主要是解决了一个模块化的问题,但是还有一个全局的样式的污染问题。我今天个人分享的就是关于PostCss的一些个人理解。

PostCss

PostCss是Autoprefixer的开发者Andrey Sitnik开发的,它最初是一个通过JavaScript来处理CSS 的方法。

可以理解为一种插件系统(类似于css领域的webpack),它本身只是一个API,作为一个API它可以创建任何需要的插件和工具。

PostCss有两个概念:pre-processor(预处理器)和post-processor(后处理器)。

像Sass、Less和Stylus都是属于预处理器的范畴,按照预处理器的语法来写css的代码,最后交由预处理器的编译器编译成一个传统的css,这个就叫做预处理器。

post-processor(后处理器)就是我们把css代码写完之后,交由它去处理,添加一些必要的属性,比如比较典型的:CSS Prefixer,会加上一些浏览器的前缀。

官方定义

PostCSS is a tool for transformimg CSS with JS plugins.

These plugins can support variables and mixins,transpile future CSS syntax,inline images,and more.

翻译过来的意思就是说呢,PostCSS是一个用JS插件转换css的工具。这些插件可以支持变量和混合,转换成未来的css语法,内联图像等。我们可以把PostCss理解成一个管道,然后在管道各处可以放一些插件,然后从管道经过的css都会经过插件的处理。实际上PostCss它将css代码转换成抽象的一个语法结构AST,就是一个对象的一个树,然后方便插件处理。

PostCss定位和使用

PostCss是一个插件系统,所以它既不是预处理器也不是后处理器,类似于css领域的webpack、Grunt和Gulp进行集成。它的作用就是整合预处理器和后处理器。

关于PostCss的使用,一般是不单独使用的,与已有的构建工具集合;比如webpack、Grunt和Gulp。

最广泛的PostCss使用是与webpack集成。

与webpack集成

1 搭建环境

  • 得到一个package.json文件
npm init

06-18-01

  • 安装webpack依赖包
npm install webpack webpack-cli --save-dev
  • --save表示会把依赖保存在package.json的文件里面来,然后-dev就会保存到devDependencies里面。
注意:”script“:{“bulid”:"webpack --config webpack.config.js"}意思就是说在运行webpack,--config表示指定配置文件,webpack.config.js 配置文件名。
  • 配置webpack.config.js

06-18-02

06-18-03

  • 打包index.js
npm run build
  • 分离css

因为要查看PostCss打包的一个效果,所以分离css是一定需要的。

需要安装的插件:

npm install css-loader --save-dev
npm install extract-text-webpack-plugin@next --save-dev
npm install postcss-loader --save-dev

PostCss 常见插件介绍

  • autoprefixer

自动添加浏览器前缀,这个插件是根据can i use解析css并且为其添加浏览器厂商前缀的PostCss插件。

caniuse(https://www.caniuse.com )是一个网站,我们可以在这个网站里面知道我们所使用的一个属性的浏览器的支持情况。

npm install autoprefixer --save-dev

安装之后添加到webpack.config.js下面的loader里面

  • stylelint

强制开发人员按照团队css规范来写css样式的工具,类似的eslint(JS的规范)。

npm install stylelint stylelint-config-lost stylelint-config-standard --save-dev

它是一个强大的,现代的linter,可以帮助您避免错误并在您的样式中强制执行约定。 为什么是强大的呢?因为它的特征:

  • 了解最新的CSS语法,包括自定义属性和4级选择器
  • 从HTML,markdown和CSS-in-JS对象和模板文字中提取嵌入式样式
  • 解析类似CSS的语法,如SCSS,Sass,Less和SugarSS
  • 拥有超过170条内置规则来捕获错误,应用限制并强制执行风格约定
  • 支持插件,因此您可以创建自己的规则或使用社区编写的插件
  • 自动修复一些违规行为(实验性功能)
  • 是很好的测试超过10000的单元测试
  • 支持可共享的配置,您可以扩展或创建自己的配置
  • 被unopinionated这样你就可以定制棉短绒您的确切需求
  • 有一个不断增长的社区,[Facebook],[GitHub]和[WordPress使用]

关于它更多的介绍可以通过(https://stylelint.io/ )官网了解一下。

  • postcss-cssnext(https://cssnext.github.io/ )
npm install postcss-cssnext --save-dev
  • postcss-modules

以模块化方式实现Css, 重点在于解决了样式冲突

npm install postcss-modules --save-dev
  • lost

强大的PostCSS网格系统

npm install lost --save-dev

文章主要介绍了PostCss的定位,结合webpack介绍了PostCss主要的几个插件:autoprefixer、postcss-cssnext、postcss-modules、lost、stylelint。文章可能存在很多不足,阅读的小伙伴们看到了可以稍作提示或者哪里有错误的可以私信告诉我纠正过来,O(∩_∩)O谢谢。

ostcss 一种对css编译的工具,类似babel对js的处理,常见的功能如:

1 . 使用下一代css语法

2 . 自动补全浏览器前缀

3 . 自动把px代为转换成rem

4 . css 代码压缩等等

postcss 只是一个工具,本身不会对css一顿操作,它通过插件实现功能,autoprefixer 就是其一。

与 less sass 的区别

less sass 是预处理器,用来支持扩充css语法。

postcss 既不是 预处理器也不是 后处理器,其功能比较广泛,而且重要的一点是,postcss可以和less/sass结合使用

如何使用

这里只说在webpack里集成使用,首先需要 loader

1 . 安装

npm install postcss-loader –save-dev

2 . webpack配置

一般与其他loader配合使用,下面*标部分才是postcss用到的

配合时注意loader的顺序(从下面开始加载)

3 . postcss配置

项目根目录新建 postcss.config.js文件,里面配置一些插件



注:也可以在webpack中配置

常用的postcss插件

1 . Autoprefixer

前缀补全,全自动的,无需多说

安装:

cnpm install Autoprefixer --save-dev

2 . postcss-cssnext

使用下个版本的css语法【关于语法另一篇文章会单独讲】

安装:

cnpm install postcss-cssnext --save-dev

3 . postcss-pxtorem

把px转换成rem

安装:

cnpm install postcss-pxtorem --save-dev

配置项:

特殊技巧:不转换成rem

px检测区分大小写,也就是说Px/PX/pX不会被转换,可以用这个方式避免转换成rem

原理

工作流

大致步骤:

  1. 将CSS解析成抽象语法树(AST树)
  2. 将AST树”传递”给任意数量的插件处理
  3. 将处理完毕的AST树重新转换成字符串

在PostCSS中有几个关键的处理机制:

Source string → Tokenizer → Parser → AST → Processor → Stringifier

Tokenizer

将源css字符串进行分词

举个例子:

.className { color: #FFF; }

通过Tokenizer后结果如下:

[
    ["word", ".className", 1, 1, 1, 10]
    ["space", " "]
    ["{", "{", 1, 12]
    ["space", " "]
    ["word", "color", 1, 14, 1, 18]
    [":", ":", 1, 19]
    ["space", " "]
    ["word", "#FFF" , 1, 21, 1, 23]
    [";", ";", 1, 24]
    ["space", " "]
    ["}", "}", 1, 26]
]

以word类型为例,参数如下:

const token = [
     // token 的类型,如word、space、comment
    'word',

    // 匹配到的词名称
    '.className',

    // 代表该词开始位置的row以及column,但像 type为`space`的属性没有该值
    1, 1,

    // 代表该词结束位置的row以及column,
    1, 10
]

Parser

经过Tokenizer之后,需要Parser将结果初始化为AST

this.root = {
    type: 'root',
    source: { input: {css: ".className { color: #FFF; }", hasBOM: false, id: "<input css 1>"},
                   start: { line: 1, column: 1 } ,
                  end: { line: 1, column: 27 }
    },
   raws:{after: "", semicolon: false}
   nodes // 子元素
}

Processor

经过AST之后,PostCSS提供了大量JS API给插件用

Stringifier

插件处理后,比如加浏览器前缀,会被重新Stringifier.stringify为一般CSS。

参考:
https://segmentfault.com/a/1190000017886402
https://www.jianshu.com/p/288963680642


作者:指尖跳动
链接:https://www.jianshu.com/p/9a9048bc8978
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。