纯原生Ajax2.0(不用FormData)实现表单及文件上传

栏目: JavaScript · 发布时间: 5年前

内容简介:通常我们用Ajax上传文件的时候都会用到表单数据可以用一下四种方式进行发送:1.method:POST,enctype:application/x-www-form-urlencoded (默认编码方式);

通常我们用Ajax上传文件的时候都会用到 FormData ,这种方式比较简单。今天介绍一种用纯Ajax上传文件的方式

表单数据可以用一下四种方式进行发送:

1.method:POST,enctype:application/x-www-form-urlencoded (默认编码方式);

2.method:POST,enctype:text/plain;

3.method:POST,enctype:multipart/form-data;

4.method:GET(enctype属性会被忽略).

若表单内容如下:

<form action="xx" method="xx" enctype="xxx" >
   foo: <input type="text" name="foo" />
   baz: <input type="text" name="baz" />
</form>
复制代码

则对于以上四种表单提交方式服务端收到的内容依次对应如下:

Content-Type: application/x-www-form-urlencoded

foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
复制代码
Content-Type: text/plain

foo=bar
baz=The first line.
The second line.
复制代码
Content-Type: multipart/form-data; boundary=---------------------------314911788813839

-----------------------------314911788813839
Content-Disposition: form-data; name="foo"

bar
-----------------------------314911788813839
Content-Disposition: form-data; name="baz"

The first line.
The second line.

-----------------------------314911788813839--
复制代码
?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
复制代码

二、纯Ajax实现

我们要实现自己的用Ajax进行表单提交,就要根据表单的method和enctype组装出提交给服务器的内容。涉及到新一些的内容有 FileReaderTypedArray 具体实现如下:

var AJAXSubmit = (function () {

    if (!XMLHttpRequest.prototype.sendAsBinary) {
        XMLHttpRequest.prototype.sendAsBinary = function (sData) {
            var nBytes = sData.length, ui8Data = new Uint8Array(nBytes);
            for (var nIdx = 0; nIdx < nBytes; nIdx++) {
                ui8Data[nIdx] = sData.charCodeAt(nIdx) & 0xff;
            }
            this.send(ui8Data);

        };
    }

    function SubmitRequest(oTarget) {
        var nFile, sFieldType, oField, oSegmReq, oFile, bIsPost = oTarget.method.toLowerCase() === "post";
        this.contentType = bIsPost && oTarget.enctype ? oTarget.enctype : "application\/x-www-form-urlencoded";
        this.technique = bIsPost ?
            this.contentType === "multipart\/form-data" ? 3 : this.contentType === "text\/plain" ? 2 : 1 : 0;
        this.receiver = oTarget.action;
        this.status = 0;
        this.segments = [];

        for (var nItem = 0; nItem < oTarget.elements.length; nItem++) {
            oField = oTarget.elements[nItem];
            if (!oField.hasAttribute("name")) { continue; }
            sFieldType = oField.nodeName.toUpperCase() === "INPUT" ? oField.getAttribute("type").toUpperCase() : "TEXT";
            if (sFieldType === "FILE" && oField.files.length > 0) {
                if (this.technique === 3) {
                    /* enctype is multipart/form-data */
                    for (nFile = 0; nFile < oField.files.length; nFile++) {
                        oFile = oField.files[nFile];
                        oSegmReq = new FileReader();
                        /* (custom properties:) */
                        oSegmReq.segmentIdx = this.segments.length;
                        oSegmReq.owner = this;
                        /* (end of custom properties) */
                        oSegmReq.onload = pushSegment;
                        this.segments.push("Content-Disposition: form-data; name=\"" +
                            oField.name + "\"; filename=\"" + oFile.name +
                            "\"\r\nContent-Type: " + oFile.type + "\r\n\r\n");
                        this.status++;
                        oSegmReq.readAsBinaryString(oFile);
                    }
                } else {
                    /* enctype is application/x-www-form-urlencoded or text/plain or
                       method is GET: files will not be sent! */
                    for (nFile = 0; nFile < oField.files.length;
                        this.segments.push(escape(oField.name) + "=" + escape(oField.files[nFile++].name)));
                }
            } else if ((sFieldType !== "RADIO" && sFieldType !== "CHECKBOX") || oField.checked) {

                this.segments.push(
                    this.technique === 3 ? /* enctype:multipart/form-data */
                        "Content-Disposition: form-data; name=\"" + oField.name + "\"\r\n\r\n" + oField.value + "\r\n"
                        : /* enctype :application/x-www-form-urlencoded or text/plain or method :GET */
                        escape(oField.name) + "=" + escape(oField.value)
                );
            }
        }
        processStatus(this);
    }

    function ajaxSuccess() {
       console.log(this.responseText);
    }

    function submitData(oData) {
        /* the AJAX request... */
        var oAjaxReq = new XMLHttpRequest();
        oAjaxReq.submittedData = oData;
        oAjaxReq.onload = ajaxSuccess;
        if (oData.technique === 0) {
            /* method:GET */
            oAjaxReq.open("get", oData.receiver.replace(/(?:\?.*)?$/,
                oData.segments.length > 0 ? "?" + oData.segments.join("&") : ""), true);
            oAjaxReq.send(null);
        } else {
            /* method:POST */
            oAjaxReq.open("post", oData.receiver, true);
            if (oData.technique === 3) {
                /* enctype:multipart/form-data */
                var sBoundary = "---------------------------" + Date.now().toString(16);
                oAjaxReq.setRequestHeader("Content-Type", "multipart\/form-data; boundary=" + sBoundary);
                oAjaxReq.sendAsBinary("--" + sBoundary + "\r\n" +
                    oData.segments.join("--" + sBoundary + "\r\n") + "--" + sBoundary + "--\r\n");
            } else {
                /* enctype is application/x-www-form-urlencoded or text/plain */
                oAjaxReq.setRequestHeader("Content-Type", oData.contentType);
                oAjaxReq.send(oData.segments.join(oData.technique === 2 ? "\r\n" : "&"));
            }
        }
    }

    function processStatus(oData) {
        if (oData.status > 0) { return; }
         submitData(oData);
       }

       function pushSegment(oFREvt) {
           this.owner.segments[this.segmentIdx] += oFREvt.target.result + "\r\n";
           this.owner.status--;
           processStatus(this.owner);
       }

       return function (oFormElement) {
           if (!oFormElement.action) { return; }
           new SubmitRequest(oFormElement);
       };
})();
复制代码

使用:

<form action="xx" method="post" enctype="multipart/form-data" onsubmit="AJAXSubmit(this); return false;" >
   foo: <input type="text" name="foo" />
   baz: <input type="text" name="baz" />
</form>
复制代码

三、用Node进行测试

const express = require('express')
const path=require('path')
const bodyParser = require('body-parser')
const multer  = require('multer')

const app = express()
const upload = multer({ dest: path.join(__dirname, '/uploads/') })

app.get('/testGet', function (req, res) {
    console.log(req.query);
  res.send('success');
})

// create application/x-www-form-urlencoded parser
app.post('/testPostDefault', bodyParser.urlencoded({ extended: false }),function (req, res) {
    console.log(req.body);
    res.send('success');
})
app.post('/testPostText', bodyParser.text({ type: 'text/plain' }),function (req, res) {
    console.log(req.body);
  res.send('success');
})
app.post('/testPostMulipart',upload.array('photos', 12), function (req, res) {
    console.log(req.files);
    console.log(req.body);
  res.send('success');
})
app.use(express.static(path.join(__dirname, 'www')));
 
app.listen(3000,function(){
    console.log('Server running at http://localhost:3000');
})
复制代码

经测试对于表单的四种提交,后端都能正确的接受到相应的数据

代码地址: github.com/fanxuewen/e…


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品型社群

产品型社群

李善友 / 机械工业出版社 / 2015-3-1 / CNY 69.00

传统模式企业正在直面一场空前的“降维战争”, 结局惨烈,或生或死。 传统模式很难避免悲惨下场, 诺基亚等昔日庞然大物轰然倒塌, 柯达发明了数码成像技术却依然破产, 新商业的兴起到底遵循的是什么模式? 微信轻而易举干掉了运营商的短信业务, “好未来”为何让传统教育不明觉厉? 花间堂为什么不是酒店,而是入口? 将来不会有互联网企业与传统企业之分, ......一起来看看 《产品型社群》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具