整合营销服务商

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

免费咨询热线:

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



在前面

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

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

自测读不读

以下是本文所涉及到的知识点,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/

些不能复制粘贴的网页该如何复制网页内容?想必有不少网络编辑和一些经常在百度复制粘贴的小伙伴们有这样的困扰,然后不知道该怎么解决的同时心中一定会默念CTMD,哈哈,有没有被言中?那不能复制的网页该如何复制呢?

一、打开想要复制内容的网页,在网页的空白处右键,出现如下图片:

二、查看源代码,将整个源代码复制粘贴到一个新建的txt文档中

三、在txt文档中找到如下代码:

<body oncopy="return false;" oncut="return false;" >

删除oncopy="return false;" oncut="return false;"(此代码的作用即为限制复制粘贴!删除即可)

四、然后点击保存,将txt文档后缀更改为*.html。下面展示具体更改后缀步骤:

右键该文档,进行重命名

将*.txt的后缀更改为html,成功后变成

然后使用浏览器打开即可,进行复制!

TIPS:可能有些人的电脑不能看到文档的后缀,只需要更改计算机里的组织里面的文件夹和搜索选项即可!操作示例图如下:

然后出现如下弹窗

点击查看,选择高级设置里面的隐藏已知文件类型的拓展名,将勾选框去掉,然后点击应用,再确定即可!再去将文件夹进行重命名是,即可修改文件后缀。

以下附更简单的办法:

将想要复制的内容,右键审查该元素,出现如下弹窗:

选定该审查元素的上一级会计元素div,右键选择

进入代码编辑之后,将该代码复制粘贴到TXT文档,保存之后直接修改后缀名为html,再使用浏览器打开即可进行复制!!!这样是不是更简单呢?

提示:飒飒用的是360浏览器做的演示,其他浏览器类似,但会有区别!

希望这边文章能够实现自由复制,不再让你为不能复制粘贴而忧心!

友情提醒:百度文库中的文档不能复制,不能用此办法解决,百度文库是用JS控制的,不能直接找到限制代码。

作前言

本章您将学会如何通过宝塔进行Apache和NGINX和虚拟主机(Apache)达到系统伪静态,这里全程以Linux宝塔伪静态为例。

什么是伪静态?

伪静态是相对于真实的静态,真正的静态会生成一个html或htm后缀文件,访问者可以访问真正的静态页面,而伪静态不会生成实体静态页面文件,而只能用.html静态类的页面形式,但它实际上是由PHP程序动态脚本处理的,它是伪静态的。静态页面的优缺点: 真正的静态通常是为了更好地缓解服务器压力,增强搜索引擎的友好性,从而使Web内容生成静态页面。但最大的缺点是,每次在网站的后台修改网页内容时,都需要重新生成静态页面,并且无法实时显示更新的内容。 网站的内容很长,占用的空间和用于生成静态页面的服务器资源是不允许的(内容太多而且一次生成静态页面的情况,导致服务器直接崩溃)。伪静态有什么作用? 有些朋友希望实时显示一些信息,或者想用动态脚本来解决一些问题,不能以静态方式显示网站内容,但这会失去搜索引擎友好的一面,两者看起来如何对于中间方法?这产生了伪静态技术。伪静态有什么不足? 由于使用伪静态来确定要跳转到的页面,而不是实际页面地址,因此区分显示哪个页面的责任也由服务器CPU直接确定。因此,CPU占用率的增加确实是伪静态的最大缺点。 NIUSHOP建议根据实际需求启用伪静态,一般情况下访问量很小,而且伪静态对CPU的影响也很小。如果访问量很大,则可以升级服务器。根据空间访问速度来选择,如国外空间建议打开真正的静态,而国内空间访问应该更快,基本上你可以选择开启伪静态。

操作前准备

操作前,我们需要到Niushop系统后台:设置—基础设置—运营—网站访问模式改为:pathinfo(详见图1-1)

(图 1-1 ↑ 网站访问模式改为:pathinfo)

服务器实战操作

  • 宝塔NGINX环境:
    找到我们建立好的站点,点击伪静态—ThinkPHP伪静态规则(通用,详见图1-2)或者选择Niushop伪静态规则—点击保存,或者直接将伪静态代码复制到编辑框中:
location / {
	if (!-e $request_filename) {
		rewrite  ^(.*)$  /index.php?s=$1  last;  
		break;
	}
}

(图1-2 ↑ NGINX伪静态规则配置)

  • Apache环境:
    找到我们建立好的站点,点击伪静态—ThinkPHP伪静态规则(通用)或者选择NIUSHOP伪静态规则—点击保存,或者直接将伪静态代码复制到编辑框中,操作基本和NGINX雷同(详见图1-2):
<IfModule mod_rewrite.c>
  Options +FollowSymlinks -Multiviews
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php?s=/$1 [QSA,PT,L]
  RewriteEngine on RewriteCond % !^$
  RewriteRule upload/(.*).(php)$ – [F]
</IfModule>

(图1-3 ↑ Apache伪静态规则配置)

  • 虚拟主机用户:
    虚拟主机环境必须是Apache ,否则无法伪静态,在根目录下找到或建立 .htaccess 这个文件,将下面的Apache伪静态规则代码复制进去并保存,如果不能新建,请点击http://suo.im/5X9IBp提取密码:ryvv(如果无效,请联系作者)进行下载并执行上传:
<IfModule mod_rewrite.c>
  Options +FollowSymlinks -Multiviews
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php?s=/$1 [QSA,PT,L]
  RewriteEngine on RewriteCond % !^$
  RewriteRule upload/(.*).(php)$ – [F]
</IfModule>

清理浏览器缓存

清理浏览器缓存后,就可以看到我们站点根目录已经被隐藏掉了,同时连接都是以html结尾,伪静态完毕!