框架基础:关于ajax设计方案(三)---集成ajax上传技术

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

概念介绍:

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

  

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

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

工具准备:

  1. 前端代码

  2. nginx服务器(分离)

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

  4. 后台代码(webAPI)

什么不多说,先贴代码:

前端代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

    /*

    *   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以下)

测试代码如下:


1

2

3

4

5

6

7

8

9

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. 未选择上传文件

文件上传成功测试

IE10、11

safari

火狐

谷歌

opera

edge

360浏览器

 下面扯一下遇到的问题

  问题一  IE8-9兼容问题

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

html代码如下:


1

2

3

4

5

6

<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

【转发自http://www.cnblogs.com/GerryOfZhong/p/6274536.html】

框架基础:ajax设计方案(三)---集成ajax上传技术

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

概念介绍:

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

  

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

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

工具准备:

  1. 前端代码

  2. nginx服务器(分离)

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

  4. 后台代码(webAPI)

什么不多说,先贴代码:

前端代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

    /*

    *   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以下)

测试代码如下:


1

2

3

4

5

6

7

8

9

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. 未选择上传文件

文件上传成功测试

IE10、11

safari

火狐

谷歌

opera

edge

360浏览器

 下面扯一下遇到的问题

  问题一  IE8-9兼容问题

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

html代码如下:


1

2

3

4

5

6

<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

【转发自http://www.cnblogs.com/GerryOfZhong/p/6274536.html】

时间: 2024-10-12 14:05:03

框架基础:关于ajax设计方案(三)---集成ajax上传技术的相关文章

框架基础:ajax设计方案(三)---集成ajax上传技术

之前发布了ajax的通用解决方案,核心的ajax发布请求,以及集成了轮询.这次去外国网站逛逛,然后发现了ajax level2的上传文件,所以就有了把ajax的上传文件集成进去的想法,ajax方案的level2的改进就不介绍了,不清楚的可到前几篇博客去看看.我们直接切入主题. 概念介绍: 1. js的FormData:js中在新的版本中已经支持了FormData对象,可以初始化一个空的form,或者初始化已经存在的form,浏览器测试代码. 2. 浏览器的支持:浏览器已支持input=file的

Ajax带进度条文件上传

Ajax带进度条文件上传 html文件代码: <html> <head> <title>FormData</title> <script type="text/javascript"> /*进度条需要两个最基础的信息------总大小,已上传大小 解决:在html5中有一个上传过程事件,在事件中可以读取这两个信息 ---- onprogress 具体思路: 在上传过程中,不断的触发函数,函数读取已上传/总大小 不断的更新页面的

Ajax+PHP实现异步图片上传

1.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Ajax+PHP实现异步图片上传</title> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <s

ajax提交带文件同步上传

我们经常为文件上传而烦恼,最烦的莫过于,要判断我们上传的文件的大小,格式等等一系列的判断验证.这种情况我们只能通过ajax提交来验证,ajax异步提交太麻烦,自己要变异太多的代码了,其实我们在使用JQuery插件的时候,它就已经帮我们想到了,它里面ajaxSubmit就很好用,表示层代码参考如下,逻辑层代码可根据个人需求自己来写: function FileChange(Value){ if(checkFormat(Value)){ document.getElementById("upload

关于云储存或者百度云的基础问题, 用java/android 实现上传文件到云储存(比如百度云)

============问题描述============ 关于云储存或者百度云的基础问题, 用java/android 实现上传文件到云储存(比如百度云) ============解决方案1============ 参考百度相关api

如何在Web页面中集成文件上传功能

当前,个人主页制作非常流行.当用户开发好自己的页面时,需要将文件传输到服务器上,解决这个问题的方法之一 是运行FTP服务器并将每个用户的FTP默认目录设为用户的Web主目录,这样用户就能运行FTP客户程序并上传文件到指定的 Web目录.由于Windows NT 和 Windows98均不提供直接的基于窗口形式的FTP客户程序,用户必须懂得如何使用基于命令行 的FTP客户,或掌握一种新的基于窗口形式的FTP客户程序.因此,这种解决方案仅对熟悉FTP且富有经验的用户来说是可行 的. 如果我们能把文件

黑马程序员 【】java学习之路——TCP(三)客户端上传文件到服务器

------- <a href="http://www.itheima.com" target="blank">android培训</a>.<a href="http://www.itheima.com" target="blank">java培训</a>.期待与您交流! ---------- import java.io.*; import java.net.*; class

从零开始学 Web 之 Ajax(三)Ajax 概述,快速上手

大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:http://www.cnblogs.com/lvonve/ CSDN:https://blog.csdn.net/lvonve/ 在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目.现在就让我们一起进入 Web 前端学习的冒险之旅吧! 一.Ajax 概述

【JS】ajax 实现无刷新文件上传

一.摘要 最近在做个东西,需要实现页面无刷新文件上传,目前看到的方法有两种 1) 通过隐藏iframe 实现页面无刷新,适用于不关心上传结果 1 <form target="hiddenFrame" method="post" enctype="multipart/form-data" action='xx'> 2 <input value=""/> 3 <iframe name="hi