纯原生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组装出提交给服务器的内容。涉及到新一些的内容有 FileReader
和 TypedArray
具体实现如下:
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…
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 表单 – 避免Symfony强制显示表单字段
- 细说 Angular 2+ 的表单(二):响应式表单
- 8款最新CSS3表单 环形表单很酷
- 动态表单 form-create 2.5 版本来啦,帮你轻松搞定表单
- 开源 | vue-form-making:基于 Vue 的表单设计器,让表单开发简单而高效
- 表单验证(AngularJs)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Building Web Reputation Systems
Randy Farmer、Bryce Glass / Yahoo Press / 2010 / GBP 31.99
What do Amazon's product reviews, eBay's feedback score system, Slashdot's Karma System, and Xbox Live's Achievements have in common? They're all examples of successful reputation systems that enable ......一起来看看 《Building Web Reputation Systems》 这本书的介绍吧!