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

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

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


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

查看所有标签

猜你喜欢:

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

iGen

iGen

Jean M. Twenge PhD / Atria Books / 2017-8-22 / USD 27.00

A highly readable and entertaining first look at how today’s members of iGen—the children, teens, and young adults born in the mid-1990s and later—are vastly different from their Millennial predecesso......一起来看看 《iGen》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具