纯原生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组装出提交给服务器的内容。涉及到新一些的内容有 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)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Java Concurrency in Practice
Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer、David Holmes、Doug Lea / Addison-Wesley Professional / 2006-5-19 / USD 59.99
This book covers: Basic concepts of concurrency and thread safety Techniques for building and composing thread-safe classes Using the concurrency building blocks in java.util.concurrent Pe......一起来看看 《Java Concurrency in Practice》 这本书的介绍吧!