前言

谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com
未经作者同意,谢绝转载,原文链接:http://huxinmin.com
谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

本文原文地址,原文链接:http://huxinmin.com

谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

本文原文地址,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com

未经作者同意,谢绝转载,原文链接:http://huxinmin.com

本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com
谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com
本文原文地址,原文链接:http://huxinmin.com
本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com

本文出自,原文链接:http://huxinmin.com

禁止非法采集,原文地址,原文链接:http://huxinmin.com

谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

禁止非法采集,原文地址,原文链接:http://huxinmin.com

未经作者同意,谢绝转载,原文链接:http://huxinmin.com

  • 本文原文地址,原文链接:http://huxinmin.com
  • 禁止非法采集,原文地址,原文链接:http://huxinmin.com

    本文出自,原文链接:http://huxinmin.com
    禁止非法采集,原文地址,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

    原文出自[胡新敏的个人博客] 转载请保留原文链接:http://huxinmin.com

    本文原文地址,原文链接:http://huxinmin.com
    本文出自,原文链接:http://huxinmin.com
    本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com
    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com
    本文出自,原文链接:http://huxinmin.com
    禁止非法采集,原文地址,原文链接:http://huxinmin.com
    未经作者同意,谢绝转载,原文链接:http://huxinmin.com
    本文出自,原文链接:http://huxinmin.com
  • 原文出自[胡新敏的个人博客] 转载请保留原文链接:http://huxinmin.com
    • 本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

    本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

    本文出自,原文链接:http://huxinmin.com

    本文出自,原文链接:http://huxinmin.com

    本文出自,原文链接:http://huxinmin.com
    禁止非法采集,原文地址,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

  • 本文原文地址,原文链接:http://huxinmin.com
  • 未经作者同意,谢绝转载,原文链接:http://huxinmin.com

    原文出自[胡新敏的个人博客] 转载请保留原文链接:http://huxinmin.com
  • 禁止非法采集,原文地址,原文链接:http://huxinmin.com
  • 本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com
  • 本文出自,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

    本文出自,原文链接:http://huxinmin.com
    本文原文地址,原文链接:http://huxinmin.com
    原文出自[胡新敏的个人博客] 转载请保留原文链接:http://huxinmin.com
    本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com本文原文地址,原文链接:http://huxinmin.com

    本文原文地址,原文链接:http://huxinmin.com

    本文原文地址,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

    本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

    本文出自,原文链接:http://huxinmin.com
    本文出自,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com

    本文出自,原文链接:http://huxinmin.com

    本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

    本文原文地址,原文链接:http://huxinmin.com

    本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com
    谢绝转载,原文地址在胡新敏的个人博客,原文链接:http://huxinmin.com本文出自,原文链接:http://huxinmin.com

    本文禁止任何形式的非法采集,原文地址:胡新敏的个人博客,原文链接:http://huxinmin.com

    一般地,文件上传有几种方式,第一种就是同步文件上传,可以使用传统的表单提交的方式,第二种就是异步文件上传的方式,如果要使用Ajax提交的话,对于一般地表单可以直接使用序列化的方式直接提交,但是对于文件格式只能使用H5的APIFormData进行文件上传,但是对于一些旧的浏览器来说,并不支持H5,那么如何在旧的浏览器中实现文件的异步上传呢?这就是我们今天要说的一种解决方案,使用iframe伪装异步文件上传。

    原理

    对于表单元素form,它具有一些如下的常见属性:

    • name规定表单的名字
    • enctype规定表单的编码方式
    • method规定表单的发送数据方法
    • action规定发送的URL地址
    • target规定在何处打开action URL

    然后我们在和表单的同一页面下,增加一个隐藏的iframe元素,让表单的target指向这个隐藏的iframe,跳转后的页面还是当前页面,就像没有刷新一样,然后后台返回的数据当前页面是iframe,只需要获取iframeparent.document即可获取原先的页面,就可以很方便地写入后台返回的信息了。

    实现

    前端页面iframe.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>iframe 文件上传</title>
    </head>
    <body>
        <h2 id='info'></h2>
        <form action='/uploadFile' method='POST' target='iframe' enctype='multipart/form-data'>
            <!-- 通过tartget设置表单提交后跳转的地方-->
            <input type='file' name='pic' />
            <input type='submit' value='提交' />
        </form>
        <iframe id="iframe" name='iframe' width='0px' height='0px' frameborder='0'>
        </iframe>
        <!-- 将iframe的高宽,边框都设置为0,相当于隐藏了-->
        <script type="text/javascript">
            var iframe = document.getElementById("iframe");
            var info = document.getElementById("info");
            //Firefox/Opera/Safari中是iframe onload事件
            //在IE下,是iframe onreadystatechange事件 
            iframe.onload = iframe.onreadystatechange = function(){
                if (this.readyState && this.readyState != "complete") return;
                else {
                     //获取iframe里面的内容
                     var responseText = iframe.contentDocument.body.textContent;
                     //上传完成后的处理
                     if(responseText!= ""){
                         info.innerHTML = responseText
                     }
                 }
            }
        </script>
    </body>
    </html>
    

    后端Nodejs版本:

    var http = require('http'),
        fs = require("fs"),
        formidable = require('formidable'),
        port = 8080
    
    http.createServer(function(req, res) {
      res.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
      if (req.url == '/uploadFile') {              //上传
        var form = new formidable.IncomingForm(),
            files = [],
            fields = [];
    
        form.uploadDir = 'upload/';
    
        form
          .on('field', function(field, value) {
            fields.push([field, value]);
          })
          .on('file', function(field, file) {
            files.push([field, file]);
            fs.renameSync(file.path, 'upload/'+file.name);
          })
          .on('end', function() {
            res.writeHead(200, {'content-type': 'text/plain'});
            res.end("上传成功");
          });
        form.parse(req, function(err, fields, files) {
            err && console.log('formidabel error : ' + err); 
        });  
      }else if(req.url == '/iframe.html'){   //发送html页面
        fs.readFile('iframe.html', function (err, data) {
          if (err) {
             console.log(err);
             // HTTP 状态码: 404 : NOT FOUND
             // Content Type: text/plain
             res.writeHead(404, {'Content-Type': 'text/html'});
          }else{             
             // HTTP 状态码: 200 : OK
             // Content Type: text/plain
             res.writeHead(200, {'Content-Type': 'text/html'});    
    
             // 响应文件内容
             res.write(data.toString());        
          }
          //  发送响应数据
          res.end();
       });   
      } else {
        res.writeHead(404, {'content-type': 'text/plain'});
        res.end('404');
      }
    }).listen(port);
    console.log('listening on http://localhost:'+port+'/');
    

    跨域上传

    上面的做法还是仅限于同域的情况,下面我们一起来学习下跨域情况下,该如何使用iframe来上传文件。

    这时候我们还需要一个前端同域的中转页面,依然是前台提交请求后跳转到隐藏的iframe,但是这次会带有一个参数,告诉后台需要重定向的地址,也就是我们的中转页面,后台重定向这个中转页面后,还会把上传后的消息通过一个参数附加在URL中。重定向的中转页面会在iframe中显示,然后在中转页面中通过parent.document获取上传页面的document元素,就可以实现跨越上传了:

    跨域上传的iframeCors.html基本代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>iframe 文件上传</title>
    </head>
    <body>
        <h2 id='info'></h2>
        <form action='http://127.0.0.1:8081/uploadFile?cb=http://127.0.0.1:8080/proxy.html' method='POST' target='iframe' enctype='multipart/form-data'>
            <!-- 通过tartget设置表单提交后跳转的地方-->
            <input type='file' name='pic' />
            <input type='submit' value='提交' />
        </form>
        <iframe id="iframe" name='iframe' width='0px' height='0px' frameborder='0'>
        </iframe>
        <!-- 将iframe的高宽,边框都设置为0,相当于隐藏了-->
    </body>
    </html>
    

    中转页面proxy.html基本代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>peoxy</title>
    </head>
    <body>
        proxy
        <script type="text/javascript">
            var mes = window.location.href.split("mes=")[1];
            parent.document.getElementById("info").innerHTML = mes
        </script>>
    </body>
    </html>
    

    后台代码:

    var http = require('http'),
        fs = require("fs"),
        formidable = require('formidable'),
        port = 8081
    http.createServer(function(req, res) {
      if (req.url.indexOf('/uploadFile')>=0) {              //上传
        var form = new formidable.IncomingForm(),
            files = [],
            fields = [];
    
        form.uploadDir = 'upload/';
        form
          .on('field', function(field, value) {
            fields.push([field, value]);
          })
          .on('file', function(field, file) {
            files.push([field, file]);
            fs.renameSync(file.path, 'upload/'+file.name);
          })
          .on('end', function() {
            var proxy = req.url.split("cb=")[1]+"?mes=上传成功"
            res.writeHead(301, {'Location': proxy});
            res.end();
          });
        form.parse(req, function(err, fields, files) {
            err && console.log('formidabel error : ' + err); 
        });  
      }else {
        res.writeHead(404, {'content-type': 'text/plain'});
        res.end('404');
      }
    }).listen(port);
    console.log('listening on http://localhost:'+port+'/');