博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【纯干货】4年前想解决的事情,今天才实验成功
阅读量:4691 次
发布时间:2019-06-09

本文共 3493 字,大约阅读时间需要 11 分钟。

第一份软件开发工作的第一个星期(不算做试用期的一个星期,无薪水试用)。因为不是软件专业,也没有经过培训和相关工作经验。老板不放心,但还是让我试一试。做的第一件事情就是上传文件,实时看进度,并且上传后预览。预览的文件类型有word,ppt,excel,flash,视频按帧获取预览图。office文件是在服务器端转成html后显示出来。

做的还满意,就留下来了,后来就在那个公司待了两年。

没解决的事情

上传大文件,分块上传,浏览器原生不支持,需要借助第三方插件。最根本的原因就是浏览器端的js考虑的安全问题,不允许读取文件内容。

现在IE10和其他主流浏览器支持html5了,js内置Filereader对象,websocket,这些听听都酷毙了。

重大意义的时刻:

我实现了原生分块上传,道路非常崎岖,结果很美好。

这一实现标识着,浏览器未来无可替代的地位。

我只介绍干货部分,其他细节,相信有兴趣的人已经知道了。

首先,分块上传,必须能在js内读取文件内容,filereader对象是关键。这是一个异步读取方法,必须在onload事件内获取文件内容。要真真的分块上传,靠onprogress读取文件进度是不够的,并且文件过大的时候浏览器会卡死。file的slice函数是关键,把文件内容分块,每一个onload事件触发,标志着一块内容读取完毕,且可以在该事件内把文件进一步处理,如上传。

FileReader有四个read方法,

asText,只建议用来读取文本文件

asDataUrl,读取到的媒体文件可以直接用于src属性,或者html文件内容也可以读成DataURL

asArrayBuffer,官方介绍说不能直接使用,需要借助DataView,如int8Array或int32Array。对于webSocket.send方法而言,ArrayBuffer和Int32Array都是可接受类型,服务端都是byte[]类型接受;如果是普通的Array数组类型,send方法内部会先转成字符串,服务端接受string类型,接受的内容形如[].join(',')转换过的值。

webSocket.send方法在onload事件中调用:

client.send(this.result);

结合slice和onload事件分块上传的核心代码:

var res = this.result;            loaded += res.byteLength;            if (loaded < fileSize)//继续读取下一块 { readBlob(loaded); times += 1; console.log("next block,times:" + times); } else { //读取完成 console.log("done loaded:" + loaded + ",size:" + fileSize); }

slice的使用方法:

function readBlob(start){    var blob = currentFile.slice(start, start + step);       reader.readAsArrayBuffer(blob);}

关于服务端可以接受的最大文件大小,主要由config的两个属性控制,MaxRequestLength和ReceiveBufferSize属性

ws = new WebSocketServer();//实例化WebSocketServer            var serverConfig = new ServerConfig();            var rootConfig = new RootConfig();            serverConfig.MaxRequestLength =  1024 * 1024 * 1024;//1MB            serverConfig.ReceiveBufferSize = 8096;            serverConfig.Ip = ip;            serverConfig.Port = port;            ws.Setup(rootConfig, serverConfig);

MaxRequestLength和ReceiveBufferSize与常见的属性不一样,不追求完美的话,MaxRequestLength设置为你希望最大可上传的文件大小即可,分块上传也不需要太大。根据测试两个属性是有关联的,即使MaxRequestLength比上传的内容小一点点,也是可以上传的。具体待有答案后再补充。

asBinaryString 现在不赞成使用的方法,且IE中也没有该方法。

如果服务器端,不支持websocket又不想使用第三方支持如superwebsocket这样组件,可以直接使用ajax真真分块上传,确定是每次请求都会建立新的连接。

使用ajax上传注意事项干货:

建议把arraybuffer转成int32array,这样客户端转换较快。服务器端用int32[]接收;如果int8array服务端也可以用int32接收。

重点:async:false 保证顺序;也可以每次上传的时候额外带参序号,服务器端重新组装顺序。

Int8array的话,服务端可以直接把每个元素转成byte

[System.Web.Mvc.HttpPost]        public ActionResult File(int[] datas)        {            if (datas != null)            {                var d = datas.ToList().ConvertAll(x => (byte)x).ToArray();            }            return Content("OK");        }

 

int32array的话,服务端可以借助bitconverter.getbytes(int)方法。

[System.Web.Mvc.HttpPost]        public ActionResult File(int[] datas)        {            if (datas != null)            {                List
bs = new List
();//接收到的文件缓冲对象 for (int i = 0; i < datas.Length; i++) { foreach (var item in BitConverter.GetBytes(datas[i])) { bs.Add(item); } } } return Content("OK"); }

ajax客户端上传关键方法:

$.ajax("/Home/File", {                data: { datas: new Int8Array(this.result) }, success: function (res) {                    console.log(res);                },                async: false,                type:"post"            });

这个调用是位于FileReader的onload事件中。

这个只是一个文件分块上传的例子,更多的好处是实时通信,如实时获取服务器端处理进度,而不用重复请求,把长连接,轮询,桥都抛在脑后吧。推送消息都成为可能。

如果觉得有意义,别忘了点【推荐】

转载于:https://www.cnblogs.com/langu/p/4478701.html

你可能感兴趣的文章
第五篇:白话tornado源码之褪去模板的外衣
查看>>
设备常用框架framework
查看>>
bootstrap模态框和select2合用时input无法获取焦点(转)
查看>>
21世纪经济网APP
查看>>
解决NetworkOnMainThreadException
查看>>
1039 到底买不买
查看>>
农银电商项目学习笔记(一)
查看>>
MockObject
查看>>
Chukwa
查看>>
(转)Maven仓库——私服介绍
查看>>
设计模式之工厂模式
查看>>
仿复制粘贴功能,长按弹出tips的实现
查看>>
Kubernetes-Host网络模式应用
查看>>
第三次作业
查看>>
使用HTML5构建iOS原生APP(2)
查看>>
sqlplus terminators - Semicolumn (;), slash (/) and a blank line
查看>>
省选知识清单/计划列表(咕?)
查看>>
远程桌面(3389)复制(拖动)文件
查看>>
转 lucene3搜索引擎,索引建立搜索排序分页高亮显示, IKAnalyzer分词
查看>>
bootstrap datetimepicker 位置错误
查看>>