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

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

内容简介:通常我们用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…


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

查看所有标签

猜你喜欢:

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

U一点·料

U一点·料

阿里巴巴集团 1688用户体验设计部 / 机械工业出版社 / 2015-7-13 / 79.00元

《U一点·料——阿里巴巴1688UED体验设计践行之路》是1688UED团队历经多年实践之后的心血之作,书中以“道─术─器”的思路为编排脉络,从设计观、思考体系、方法论上层层剖析,将零散的行业knowhow串成体系,对“UED如何发展突破”提出了自己的真知灼见。该书重实战、讲方法、求专业、论文化,是一部走心的诚意之作。 本书作者从美工到用户体验设计师,从感性随意到理性思考,从简单的PS做图到......一起来看看 《U一点·料》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

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

在线 XML 格式化压缩工具

html转js在线工具
html转js在线工具

html转js在线工具