Talking about the methods of three kinds of non-refreshing uploading files based on IFrame, FormData and FileReader _javascript skills

Source: Internet
Author: User
Tags http post

There are two ways to send a request, one is Ajax, the other is a form submission, and the default form submission, if not handled, will redirect the page. Explain with a simple demo:


The HTML looks like this, the requested path action is "upload", and the other does not do any processing:

 <form method= "POST" action= "Upload" enctype= "Multipart/form-data" >
  name <input type= "text" name= "user" ></input>
  Avatar <input type= "file" name= "file" ></input>
  <input type= "Submit" id= "_ Submit "Value=" ></input>
 

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

You can see that by default, form requests upload to upload at the same time. But in many cases, you want the form request to be like Ajax, without redirecting or refreshing the page. Like the above scene, when the upload is complete, the user's selected avatar is displayed on the current page.

The first solution is to use the HTML5 formdata, to encapsulate the data in the form into the Formdata object, and send it as a post. As shown in the following code, a response is made to the Click event of the Submit button, line 6th gets the DOM object of the form, and then line 8th constructs an instance of Formdata, row 18th, to send the form data.

document.getElementById ("_submit"). onclick = function (event) {
   //cancel default form Submit mode
   if (event.preventdefault) Event.preventdefault ();
   else Event.returnvalue = false;       For IE cancellation mode
   var formdom = document.getelementsbytagname ("form") [];
   Use the DOM object of form as the FormData constructor
   var formData = new FormData (formdom);
   var req = new XMLHttpRequest ();
   Req.open ("POST", "upload");
   Request Complete
   req.onload = function () {
    if (this.status = =) {
      //To request successful processing
    }
   }
   //Send form data out      
   req.send (formData);
Avoid memory leaks
req = null;
 

After the upload is successful, the service will return the image's access address and add 14 lines to the successful processing of the request: Display the uploaded picture above the submit button:

var img = document.createelement ("img");
     IMG.SRC = Json.parse (this.responsetext). path;
     

Example:


If you use jquery, you can take formdata as the data parameter for Ajax, and set up Contenttype:false and processdata:false to tell jquery not to handle the request headers and the data sent.

It looks like Ajax, but not exactly the same, the form submitted by the data format has three, if you want to upload the file must be Multipart/form-data, So the above form submits the HTTP header information inside the Content-type for Multipart/form-data, while ordinary Ajax is submitted as Application/json. Form submits the complete Content-type as follows:

"Content-type": "Multipart/form-data;" boundary=------WEBKITFORMBOUNDARYYOE7PWLQDFYSEBFJ "

In addition to Multipart/form-data, the boundary is also specified, which is used to differentiate between different fields. Because the Formdata object is opaque, calling Json.stringify returns an empty object {}, and Formdata only provides the Append method, so it cannot get what the Formdata actually preached, However, you can view the data that is received by the Profiling tools or services. If you upload a text file above, the original format of the post data that the service receives is this:

------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 from the above service shows the format of the Formdata submission, with each field separated by boundary and finally ending. The AJAX request, send out of the data format is customized, is generally used in the middle of the Key=value & connection:

 var req = new XMLHttpRequest ();
  var senddata = "User=abc&file= This is the inner content of a text file";
  Req.open ("POST", "upload");
  The data sent needs to be escaped, as shown in the three formats mentioned above
  ("Content-type", "application/x-www-form-urlencoded"); Req.setrequestheader
  

The service receives exactly the same as the string sent by send and then parses the argument so that the format of the unified parameter is obtained:

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

From here you can see that post is inherently no better than get security, post just did not put the data on the URL to send it.

Considering the Formdata to IE10 only support, if you want to support the lower version of IE, you can use the IFRAME.

In the beginning, the default form submission causes the page to be redirected, and the redirected rule is specified in target, can be specified as "_blank" as the A label, opened in a new window, and can be specified as an IFRAME, opened in the IFRAME. So you can get a hidden iframe that points to the iframe of the form, and when the form request completes, the returned data is displayed by the IFRAME, as shown on the new page: "Recieved form data." After the request completes, the IFRAME completes the load, triggers the Load event, and obtains the content of the IFRAME in the processing function of the load event, thus getting the data returned by the service! Get it and then delete the IFRAME.

In the response function of the Submit button, first create an IFRAME, set the IFRAME to invisible, and then 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");
  Put it in document.
  

Change the name value of the form's target to IFRAME:

 

Then respond to the IFRAME's Load event:

 Iframe.onload = function () {
   var img = document.createelement ("img");
   Gets the content of the IFRAME, which is the data returned by the service
   var responsedata = this.contentDocument.body.textContent | | this.contentWindow.document.body.textContent;
   IMG.SRC = Json.parse (responsedata). path;
   F.insertbefore (IMG, document.getElementById ("_submit"));
   Erase the IFRAME
   settimeout (function () {
    var _frame = document.getElementById ("Form-iframe");
    _frame.parentnode.removechild (_frame);
   If you are prompted to submit the function does not exist, please note whether there is a Id/value control
   this.form.submit () in the form;
  

The second way to the basic can be here, but if you look at the 163 mailbox or QQ mailbox upload file way, will find and the above two methods are not the same. Using Httpfox to crawl the requested data, you will find that the content of the upload is not the above said by boundary separated, but directly to the contents of the file post out, and the file name, size and other related information on the head of the file. such as 163 mailbox:

POST Data:

This is a text

Headers:

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

It can be speculated that they should read the contents of the input file directly, and then post it directly. To achieve such a function, you can use FileReader, read the contents of the input file, and then keep the binary format to send out:

 var req = new XMLHttpRequest ();
   Req.open ("POST", "upload");
   Set the same Content-type Req.setrequestheader as the mailbox
   ("Content-type", "Application/octet-stream");
   var fr = new FileReader ();
   Fr.onload = function () {
    req.sendasbinary (this.result);
   }
   Req.onload = function () {
     //Same, omit
   }  //Read input file contents, put into filereader result field  
   

Line 13th of the code reads the file, triggers the load response function on line 6th after reading, and the 7th line is sent as binary text. Because sendasbinary support is not very good, you can implement one 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 is the 6th line, which converts the string into a 8-bit unsigned integer and restores the contents of the binary. After the fr.readasbinarystring is executed, the contents of the binaries are stored as strings to result in Utf-8 encoding, and the 6th line of code converts each Unicode encoding to an integral type (&0xff or parseint). stored in a 8-bit unsigned integer array, line 8th sends the array. If you send directly, instead of Sendasbinary, the data received by the service will not revert to the original file as expected.

The above implementation needs to consider the file is too large, need to be segmented upload problem.

With respect to FileReader support, IE10 above support, IE9 has another set of file APIs.

The article discusses 3 ways to achieve no refresh upload files, respectively, using IFRAME, Formdata and FileReader, the best support is the IFRAME, but from the effect of experience to see Formdata and FileReader better, Because these two do not generate a useless dom and then delete, which formdata the simplest, and filereader more flexible.

Next to introduce you to the IFRAME no refresh upload file

form.html
<form enctype= "Multipart/form-data" method= "post" target= "Upload" action= "upload.php" > 
<input type= "File" name= "UploadFile"/> <input type=
"Submit"/> 
</form> 

<!--a target attribute that specifies where the tab page opens and submits the data, compared to the general <form> tag.

If this property is not set, the URL in the action will be redirected to open on this page as usual.

If set to the name of the IFrame, that is, "upload", it will open in the IFRAME, because the CSS is set to hidden, so there will be no movement. If you remove the Display:none, you will also see the server's return information.

--> upload.php <?php Header ("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 if the file was uploaded via HTTP POST//If the file given by FileName is uploaded via an HTTP post, return TRUE. 
  This can be used to ensure that malicious users cannot spoof scripts to access files that cannot be accessed, such as/etc/passwd. 
  if (!is_uploaded_file ($this->_file[' tmp_name ')) throw new Exception ("exceptional condition"); 
 if ($this->_file[' error ']!==) throw new Exception ("Fault code:". $this->_file[' errors ')); The 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 "<script type= ' text/javascript ' >alert (' upload success ') </script>"; } PUBlic function Checkdir ($dir) {if (!file_exists ($dir)) {mkdir ($dir, true); 
 Return Realpath ($dir);
}} $upload =new upload ();
$new _dir= "./a/b"; $upload->moveto ($new _dir);

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.