About how to upload a file without refreshing, such as iframe, FormData, and FileReader _ javascript skills

Source: Internet
Author: User
There are two ways to send requests: ajax and form. The default form will redirect the page if it is not processed. This article uses examples to introduce three methods for uploading files without refreshing the content based on iframeFormDataFileReader. If you are interested, you can learn how to send requests through ajax, the other is to use form for submission. If the default form for submission is not processed, the page will be redirected. The following is a simple demo:


The Request Path action is "upload", and others are not processed as follows:

  

The server (node) response directly returns: "Recieved form data", as shown below:

By default, you can see that the form request is redirected to the upload at the same time. However, in many cases, it is hoped that the form request will not be redirected or refreshed like ajax. In the preceding scenario, after the upload is complete, the user-selected avatar is displayed on the current page.

The first solution is to use FormData of html5 to encapsulate the data in form into the FormData object, and then send the data in POST mode. As shown in the following code, a response is made to the Click Event of the submit button. Line 3 of the Code obtains the DOM object of form, and line 3 constructs an instance of FormData, line 3, send form data.

Document. getElementById ("_ submit "). onclick = function (event) {// cancel the default form submission method if (event. preventDefault) event. preventDefault (); else event. returnValue = false; // The method for canceling IE is var formDOM = document. getElementsByTagName ("form") []; // treats the form DOM object as the FormData constructor var formData = new FormData (formDOM); var req = new XMLHttpRequest (); req. open ("POST", "upload"); // The request completes req. onload = function () {if (this. status ==) {// successful request processing} // send form data out of req. send (formData); // prevent memory leakage req = null ;}

After the upload is successful, the service will return the access address of the image and add 14 lines for successful request processing: The uploaded image is displayed at the top of the submit button:

var img = document.createElement("img");     img.src = JSON.parse(this.responseText).path;     formDOM.insertBefore(img, document.getElementById("_submit")); 

Example:


If jQuery is used, formData can be used as the ajax data parameter, and contentType: false and processData: false can be set at the same time, telling jQuery not to process request headers and sent data.

It seems that this submission method is the same as ajax, but it is not exactly the same. There are three data formats submitted by form. to upload a file, it must be multipart/form-data, therefore, the Content-Type in the http header in the form submission request above is multipart/form-data, while the normal ajax submission is application/json. The complete Content-Type submitted by form is as follows:

"Content-type": "multipart/form-data; boundary = ------ WebKitFormBoundaryYOE7pWLqdFYSeBFj"

In addition to multipart/form-data, boundary is also specified. This boundary is used to differentiate different fields. Because the FormData object is not transparent, JSON is called. stringify returns an empty object {}. Meanwhile, FormData only provides the append method, so you cannot get the actual content uploaded by FormData. However, you can view the data received by the analysis tool or service. If you upload a text file above, the original format of the POST data received by the service is as follows:

------ WebKitFormBoundaryYOE7pWLqdFYSeBFj

Content-Disposition: form-data; name = "user"

Abc

------ WebKitFormBoundaryYOE7pWLqdFYSeBFj

Content-Disposition: form-data; name = "file"; filename = "test.txt"
Content-Type: text/plain

This is the content of a text file.

------ WebKitFormBoundaryYOE7pWLqdFYSeBFj --

The data received by the above service shows the format of FormData submission. Each field is separated by boundary and ends. For ajax requests, the data format sent out is customized. Generally, they are connected with & in the middle of key = value:

Var req = new XMLHttpRequest (); var sendData = "user = abc & file = This is the content in a text file"; req. open ("POST", "upload"); // The sent data needs to be escaped. See the three formats mentioned above for req. setRequestHeader ("Content-Type", "application/x-www-form-urlencoded"); req. send (sendData );

The Service will receive the same content as the string sent by send, and then parse the parameters. Therefore, you must unify the parameter format:

User = abc & file = This is the content of a text file.

It can be seen from this that POST is essentially not more secure than GET. POST simply does not transmit data on the website.

It is supported only when FormData reaches IE10. To support earlier versions of IE, you can use iframe.

In this article, the default form commit will redirect the page, and the redirection rule is specified in the target, which can be specified as "_ blank" like the tag ", open in a new window. You can also specify an iframe to open in this iframe. Therefore, you can obtain a hidden iframe and direct the target of the form to this iframe. When the form request is complete, the returned data is displayed by this iframe, as shown on the new page: "Recieved form data ". After the request is complete, iframe is loaded and the load event is triggered. In the load event processing function, get the content of the iframe and get the data returned by the service! And then delete the iframe.

In the response function of the submit button, create an iframe, set iframe to invisible, and add it to the document:

Var iframe = document. createElement ("iframe"); iframe. width = 0; iframe. height = 0; iframe. border = 0; iframe. name = "form-iframe"; iframe. id = "form-iframe"; iframe. setAttribute ("style", "width: 0; height: 0; border: none"); // place it in document this. form. appendChild (iframe );

Change the target of form to the name of iframe:

 this.form.target = "form-iframe"; 

Then, respond to the iframe load event:

Iframe. onload = function () {var img = document. createElement ("img"); // obtain the iframe content, that is, the data returned by the Service var responseData = this. contentDocument. body. textContent | this.content+doc ument. body. textContent; img. src = JSON. parse (responseData ). path; f. insertBefore (img, document. getElementById ("_ submit"); // Delete iframe setTimeout (function () {var _ frame = document. getElementById ("form-iframe"); _ frame. parentNode. removeChild (_ frame) ;}, 100); // If the submit function does not exist, check whether the form contains the submit control with the id/value. this. form. submit ();}

The second method can be used here. However, if you use the 163 email or QQ email to upload files, you will find that the two methods are not the same. When you capture the requested data with httpfox, you will find that the format of the uploaded content is not separated by boundary, but directly POST the content of the file, the file name, file size, and other information are placed in the file header. For example, email 163:

POST Data:

This is a text

Headers:

Mail-Upload-name: content.txt
Mail-Upload-size: 15

It can be inferred that they should directly read the content of the input file, and then directly POST it out. To implement this function, you can use FileReader to read the content of the input file and then retain the binary format for sending:

Var req = new XMLHttpRequest (); req. open ("POST", "upload"); // set Content-Type req. setRequestHeader ("Content-Type", "application/octet-stream"); var fr = new FileReader (); fr. onload = function () {req. sendAsBinary (this. result);} req. onload = function () {// Similarly, omitted} // read the content of the input file and put it in the result field of fileReader fr. readAsBinaryString (this. form ["file"]. files [0]);

Code 13th executes the Read File, triggers the load response function of line 6th after reading, and sends the load response function of line 7th in the form of binary text. Because sendAsBinary is not well supported, You can implement one by yourself:

 if(typeof XMLHttpRequest.prototype.sendAsBinary === 'undefined'){  XMLHttpRequest.prototype.sendAsBinary = function(text){  var data = new ArrayBuffer(text.length);  var uia = new UintArray(data, );  for (var i = ; i < text.length; i++){    uia[i] = (text.charCodeAt(i) & xff);  }  this.send(uia);  } } 

The key to the code lies in the 6th lines. Convert the string into an unsigned integer and restore the binary file. Fr. after readAsBinaryString, the binary file content will be stored as a string in UTF-8 encoding to the result. The above 6th lines of code convert each unicode encoding to an integer (& 0xff or parseInt ), store it in an 8-bit unsigned integer array, and the array is sent out in row 8th. If you send data directly instead of sendAsBinary, the data received by the service cannot be restored to the original file.

The above implementation requires that the file is too large and multipart upload is required.

For the support of FileReader, IE10 or above, IE9 has another set of File APIs.

The article discussed three methods to achieve non-Refresh upload of files, namely using iframe, FormData, and FileReader. The best support is iframe. But from the experience, FormData and FileReader are better, because the two do not need to generate a useless DOM and then delete it. FormData is the simplest, while FileReader is more flexible.

The following describes how to upload a file without refreshing iframe.

form.html  

Upload. php <? Phpheader ("Content-type: text/html; charset = utf-"); class upload {public $ _ file; public function _ construct () {if (! Isset ($ _ FILES ['uploadfile']) {$ name = key ($ _ FILES);} if (! Isset ($ _ FILES ['uploadfile']) {throw new Exception ("No File Upload ");} $ this-> _ file = $ _ FILES ['uploadfile']; // $ this-> _ file one-dimensional array var_dump ($ this-> _ file ); // determine whether the file is uploaded through http post. // if the file given by filename is uploaded through http post, TRUE is returned. This can be used to prevent malicious users from spoofing scripts to access files that cannot be accessed, such as/etc/passwd. If (! Is_uploaded_file ($ this-> _ file ['tmp _ name']) throw new Exception ("Exception "); if ($ this-> _ file ['error']! =) Throw new Exception ("error code :". $ this-> _ file ['error']);} public function moveTo ($ new_dir) {$ real_dir = $ this-> checkDir ($ new_dir ). '/'; $ real_dir = str_replace ("\", "/", $ real_dir); if (! Move_uploaded_file ($ this-> _ file ['tmp _ name'], $ real_dir. $ this-> _ file ['name']) {exit ('upload failed');} echo"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.