前端通讯:ajax设计方案(三)--- 集成ajax上传技术

在此以前让我感慨一下如今的前端开发的氛围。我遇到好多人,给个人观念都是,这个东西这个框架有了,那个东西那个框架作了,前端嘛,学几个框架,这个拼凑一下那个拼凑一下就行了。其实我想问,东西都框架作了,那你会什么?会吹牛逼?会撕逼?javascript

我在简历上写专一原声js,曾经被几我的笑过。我一直搞不懂,框架会过期,基础永远不会过期。离了框架,我能够活,我也会本身写框架,我也在前端模块化的路上本身摸索着,我也在前端如何更简单,更快速开发的路上摸索着。难道有框架作了,我就坐吃山空等死吗?html

前端太浮躁,我也无所谓成为别人眼中的奇葩。我去作前端,我去作分离,我去写后端,天天总会花一些时间在我喜欢的东西上。我知道我很傻逼,有的玩不玩,还去看代码。那我没办法,我作奇葩很长时间了,由于我有本身的梦想,我有本身的追求。前端

请不要在我面前说,你这个东西人家都作了。作了怎么了?人家作了,是你的吗?人家作的时候前面不也有千千万万个死的淘汰的东西吗?难道就由于人家作了我就不干了?请不要目光短浅。鄙人也不隐藏我为何作前端,如今列举我作前端的理由,你和我同样吗?html5

    1. 对接UI,须要涉猎页面设计,布局和美化。学会去审美,学会站在用户角度去看本身的东西。固然我不否定,UI妹子也多
    2. 对接js,对前端核心技术的考验。对于页面功能实现、新旧技术兼容和舍弃、如何写出高效可维护代码的思考
    3. 对接架构,前端性能优化,程序健壮性和容错性,各类框架资源整合使用,从DNS解析到页面渲染到你眼前的各类过程的跨域学习
    4. 对接后端,新老技术的变化,永远不是前端,后端同样须要去配合着去改变。因此懂后端,设计后端,写后端,永远都须要你去懂得
    5. 对接服务器,反向代理,负载均衡,请求分发容错整合等等难道不须要懂吗?难道只敲个js就够了?
    6. 前端的将来,任何项目的使用和展现,都离不开前端。由于前端第一接触是用户,是发展的最核心的资源。前端是站在整个战线第一线的。
    7. 最重要的。前端刚起步,不是很成熟,能够接触全部的原声和底层,优化,开发,调试,甚至改变世界,都是有可能的。后端太成熟,接触太多都是框架,突出重围,须要更深的积累和叛逆。
    8. 最重要的,前端相对来讲,薪水前期仍是很好的。毕竟还要生活,诗和远方都不及面包重要,活着,一切才有可能。

 

  以前发布了ajax的通用解决方案,核心的ajax发布请求,以及集成了轮询。此次去外国网站逛逛,而后发现了ajax level2的上传文件,因此就有了把ajax的上传文件集成进去的想法,ajax方案的level2的改进就不介绍了,不清楚的可到前几篇博客去看看。咱们直接切入主题。java

 

概念介绍:nginx

  1. js的FormData:js中在新的版本中已经支持了FormData对象,能够初始化一个空的form,或者初始化已经存在的form,浏览器测试代码。git

  

 

  2. 浏览器的支持:浏览器已支持input=file的时候查看文件,具体包括文件的大小(size)和类型(type),浏览器测试以下github

 

  3. xmlhttprequest:支持发送(send方法)新的数据类型,包括DOMStringDocumentFormDataBlobFileArrayBuffer。具体参见ajax设计方案的规范web

 

工具准备:ajax

  1. 前端代码

  2. nginx服务器(分离)

  3. IIS服务器(部署后台)

  4. 后台代码(webAPI)

 

什么很少说,先贴代码:

前端代码:

        /*
        *   ajax上传文件
        *       url                 文件上传地址
        *       fileSelector        input=file 选择器(支持多文件上传,只要后台接口支持)
        *       size                文件限制大小
        *       fileType            文件限制类型 mime类型
        *       success             上传成功处理
        *       error               上传失败处理
        *       timeout             超时处理
        *
        *   return: status:  0      请选择文件
        *                    1      超出文件限制大小
        *                    2      非容许文件格式
        * */
        upload:function(url,fileSelector,size,fileType,success,error,timeout){
            var formdata = new FormData(),fileNode = document.querySelector(fileSelector),fileCount = fileNode.files.length,data={},result ={};
            //如下为上传文件限制检查
            if ( fileCount > 0 ){
                tool.each(Array.prototype.slice.call(fileNode.files),function(value){
                    //检查文件大小
                    if (value.size > size){
                        result["status"] = 1;
                        result["errMsg"] = "超出文件限制大小";
                    }else{
                        //检查文件格式.由于支持formdata,天然支持数组的indexof(h5)
                        if (fileType.indexOf(value.type)=== -1 ){
                            result["status"] = 2;
                            result["errMsg"] = "非容许文件格式";
                        }else{
                            formdata.append(value.name,value);
                        };
                    };
                });
            }else{
                result["status"] = 0;
                result["errMsg"] = "请选择文件";
            };

            if (result.status !== undefined)  return result;   //若是有错误信息直接抛出去,结束运行

            var ajaxParam ={
                type:"post",
                url:url,
                data:formdata,
                isFormData:true,
                success:success,
                error:error,
                timeout:timeout
            };
            ajax.common(ajaxParam);
        },
    };

后端接口代码(C#的webAPI),代码比较简陋,能完成测试就好

    [Route("upload3")]
        public async Task<HttpResponseMessage> PostFormData()
        {
            // Check if the request contains multipart/form-data.
            // 检查该请求是否含有multipart/form-data
            if (!Request.Content.IsMimeMultipartContent())
            {
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
            }

            string root = HttpContext.Current.Server.MapPath("~/uploadfile");
            var provider = new ReNameMultipartFormDataStreamProvider(root);

            try
            {
                // Read the form data.
                // 读取表单数据
                var task = await Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t =>
                {
                    if (t.IsFaulted || t.IsCanceled)
                    {
                        Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
                    }
                    string fileName = string.Empty;
                    foreach (MultipartFileData file in provider.FileData)
                    {
                        fileName = file.LocalFileName;
                    }
                    //返回上传后的文件全路径
                    return new HttpResponseMessage() { Content = new StringContent(fileName) };
                });
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (System.Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
            }
        }

        ///
        /// 重命名上传的文件
        ///
        public class ReNameMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
        {
            public ReNameMultipartFormDataStreamProvider(string root)
                : base(root)
            { }
            public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
            {
                //截取文件扩展名
                string exp = Path.GetExtension(headers.ContentDisposition.FileName.TrimStart('"').TrimEnd('"'));
                string name = base.GetLocalFileName(headers);
                return name + exp;
            }
        }

 

浏览器测试结果(几乎全部主流浏览器都支持,除了IE10如下)

测试代码以下:

            var temp = ajax.upload("/api/ajaxUpload/upload3/", "#file1", 1024 * 1024 * 1, ["image/png","image/bmp"], function (data) {
                if (data == "true") {
                    alert("上传成功!");
                }
                if (data == "error") {
                    alert(data);
                }
            });
            console.log(temp);

格式限制测试结果以下

1. 选取超过限制大小的文件

2. 选取非容许格式的文件

3. 未选择上传文件

 

 

文件上传成功测试

IE十、11

safari

火狐

谷歌

opera

edge

360浏览器

 

 

 下面扯一下遇到的问题

  问题一  IE8-9兼容问题

在兼容性网站(http://caniuse.com/)查询兼容性,ajax leve2支持IE10+版本,因此若是在IE8-9上使用纯前端代码进行上传文件的话,只有传统的form标签

html代码以下:

<form id="formUpload" action="/api/ajaxUpload/upload2/" method="post" enctype="multipart/form-data" target="framFile">
    <input name="isIE8" type="text" value="1" readonly style="display: none"/>
    <input id="iefile" type="file" name="age"/>
    <input type="submit" value="submit">
</form>
<iframe id="framFile" name="framFile" src="postMsg.html"></iframe>

缺点:

1. 每次form提交的时候都会刷新页面,若是想作异步无刷新,用iframe作提交页面

2. IE8-9没法在前端对文件进行大小和类型检查(使用IE的文件组件不安全,由于能够修改系统上全部文件,容易被攻击,并且浏览器都是默认关闭的)

3. 上传文件接口不能有返回值,不然在IE8下会将接口返回值做为文件下载下来,且没法取得返回值(用了N种方法),可是在其余浏览器中ajax的成功事件会去作判断,测试图片以下 

一些建议:若是真的要作IE8-9,如今广泛的方案是将flash插件和ajax Level2的上传进行组合,支持H5的用ajax上传,不支持初始化flash上传插件。

PS:对于那些偏执的,必定要在IE8-9用纯前端代码支持上传的,还有一种折中的方案,和这种思想相似,可是我作了优化,思路以下:

须要2个接口:上传文件接口,IE8-9下上传结果查询接口

a. 首先使用form的无刷新上传(ifarme)

b. 后台接收到formdata数据判断是不是IE8-9的上传,是的话将该用户上传文件是否成功的状态改变(无论存库或者其余地方),不然直接返回上传结果

c. 前端在form的submit以后,发起获得一次结果的轮询,若是获得结果,则直接结束轮询,结果查询接口也将该用户的上传文件状态清空

 

  问题二  通常ajax请求和formdata请求,后台取值问题。

传统http请求,能够直接在接口参数中取得数据,可是使用formdata进行ajax请求的话,后台接口须要从formdata对象中取数据,包括文件啥的。由于这个我写后台接口的时候就懵逼了好长一段时间,而后左查查右查查,终于明白取值方式也不同了。

 

  问题三  关于formdata上传文件,具体能上传多大文件的限制问题

上传文件的限制取决于web容器可接受上传文件的大小,tomcat、IIS等web容器都有本身的设置方法,具体可搜索引擎,你懂的

 

  问题四  前端对大文件的传输解决方案,具体可参考该文章

在新的版本中,就是支持H5的版本中,有了File对象能够切割文件,由于在取到input=file中取到的文件都是File类型,File对象有个方法slice,能够切割文件,而后分配一个xhr上传。主要是后台的切割文件重组问题不是很清楚,因此我暂时也没有集成大文件上传方法。

 

 代码已集成github:https://github.com/GerryIsWarrior/ajax     点颗星星是我最大的鼓励,有什么问题能够博客、邮箱、github上留言

 

这一次上传版本,代码作过变更,变更以下:

  1. 增长FormData数据传输方法(postFormData),若是判断到浏览器不支持FormData,则自动使用默认原始的数据传输
  2. 新增各类类型判断方法,判断类型
  3. 更新each方法,判断若是传入参数obj为数组并且浏览器支持h5的新特性直接用数组的forEach方法

 

个人全栈书签,此次更新整理了国内顶级互联网和著名的一些互联网公司的招聘网站,但愿你们找到好工做,^_^

github地址:https://github.com/GerryIsWarrior/MyBookmarks

相关文章
相关标签/搜索