Problems encountered by jQuery+formdata in implementing upload progress effects

  • 2021-01-02 21:46:33
  • OfStack

Summarize the technical problems I encountered in making the HTML5 file upload plugin

First paste the source code: ES4en-html5.ES6en (PS: the company uses the seajs framework)

Question list

1. JQUERY.AJAX does not listen for ONPROGRESS events of upload progress.

2. XMLHTTPREQUEST (XHR) cross-domain

Problem solving

1. JQUERY does not give an interface for the ONPROGRESS event, and the native XHR object must be found in another interface.

jQuery. ajax() returns the jqXHR object. jqXHR mimics XHR(native) but does not emulate all the methods and attributes that implement XHR (e.g.,.upload), even though jqXHR adds a unique method (e.g.,.promise ()). So jqXHR is not a superset of XHR.


// Here is the interception jQ The internal source code, $.ajax(); That's what I'm going to get back jqXHR (fake XMLHttpRequest ) 
// Fake xhr
 jqXHR = {

  readyState: 0,


The upload property of XHR points to XMLHttpRequestUpload (IE10 is XMLHttpRequestEventTarget), where the onprogress event can listen for upload progress. Since jQ does not provide api for this function, jQ uses XHR for some data uploads, so we can find XHR from other api. The upload progress function can be achieved by binding onprogress events before XHR sends data.

I found two properties related to XHR from the OPTIONS parameter configuration:

-ES64en: Callback creates the XMLHTTPREQUEST object.

The return value of xhr() is XHR and is provided to jQ, that is, XHR is used to send data. We can override this by creating a callback function with xhr that returns XHR again, but binds the onprogress event here.


//jQ The source code 
// Get a new xhr
var handle, i,
 xhr = s.xhr();//[ The callback ] Here it is. Here it is open methods 

// Open the socket
// Passing null username, generates a login popup on Opera (#2865)
if ( s.username ) {
 xhr.open( s.type, s.url, s.async, s.username, s.password );
} else {
 xhr.open( s.type, s.url, s.async );
}

So here's what we should do:


$.ajax({
 //.....
 xhr: function() {
  var xhr = $.ajaxSettings.xhr();
  // Binds the upload progress callback function 
  xhr.upload.addEventListener('progress', progress, false);
  return xhr;//1 You must return, or else jQ There is no XHR Objects using the 
 }
});

-ES81en: 1 mapping to filename - file value for setting native XHR objects.

The xhrFields attribute points to XHR created within jQ, and we can obtain XMLHttpRequest based on xhrFields. Since the value of xhrFields can only be an json object, it cannot be obtained in the following manner.


// The wrong case 
$.ajax({
 //......
 xhrFields: {
  upload.onprogress: function() {
   // Grammar mistakes 
  }
 }
});

We can use the onsendstart event of XHR, as follows:


$.ajax({
 //......
 xhrFields: {
  onsendstart: function() {
   //this Is pointing to XHR
   this.upload.addEventListener('progress', progress, false);
  }
 }
});

2. XMLHTTPREQUEST Ⅱ (XHR) supports cross domain, but need the background.


// The background needs to send header validation 
if($_REQUEST['cros']) {
 header("Access-Control-Allow-Origin: Requested domain name ");
}

According to the interface given by the background, I need to add 1 parameter cros. However, I submitted this parameter with a file colleague, prompting cross-domain limitations. Finally, put this parameter on url.

The original XHR cross-domain had two requests, the first was the authentication request, and the browser automatically issued the options request according to the destination address of the request. If passed, the custom post request can only be issued. Therefore, the parameter is put in the post request. The first request does not have the cros parameter, that is, it cannot pass.


Related articles: