Search code examples
nginxhttp2

HTTP2 Nginx server 200 response for XHR POST Request to a Static FILE


Strange behavior with HTTP2 when trying to send POST request to a static file on a Nginx server. immediately getting 200 response without sending the whole data on HTTP2 and uploading the whole file without any issue on HTTP1.1.

When i change upload path to "upload.php" everything working fine on HTTP2 and 1.1 . Problem occurs when we try to send POST request to "upload.bin" or "upload" a static file with or without extension on HTTP2.

<body>
  <input type="file" id="file-input" />
  <button id="upload-button">Upload File</button>
  <div id=live></div>
  <div id=live2></div>
  <script type="text/javascript">

var live = document.getElementById('live');
  var live2 = document.getElementById('live2');
    document.querySelector('#upload-button').addEventListener('click', function() {
        if(document.querySelector('#file-input').files.length == 0) {
            alert('Error : No file selected');
            return;
        }

        let file = document.querySelector('#file-input').files[0];
        let allowed_mime_types = [ 'application/zip', 'image/png' ];
     

        let data = new FormData();
        data.append('file', document.querySelector('#file-input').files[0]);

        let request = new XMLHttpRequest();
        request.open('POST', 'upload'); 
        request.upload.addEventListener("progress", progressHandler, function(e) {  
            
        });
        request.send(data);

    function progressHandler(event){
      live.innerHTML = "Event.Loaded = " + event.loaded;
      var percent = (event.loaded / event.total)*100;
      live2.innerHTML = "Progress percent = " + percent;
    }
    });

to handle post to static file in Nginx config.

error_page  405     =200 $uri;

Why NGINX is behaving like this to a POST request with HTTP2 ?


Solution

  • This is intentional.

    NGINX knows that your renderer for a 405 error doesn't need any body, so with HTTP, it discards any received data. This is really how HTTP1.1 has been designed.

    With HTTP2, it becomes smarter, it tells the other side to abort sending data, and sends the resulting page. This is done to prevent wasting internet packets for data that is going to be discarded anyway.

    The way HTTP2 and higher works, is just smarter and wastes less of your data for things that are already known (for example, if you need to login for a file upload, it just tells the client as soon as possible that there is an error, instead waiting until your full file has been uploaded)

    When you send a request to a .php file, the php process takes it over, and it doesn't have a way to instantly return a result, so NGINX streams the whole page to php before showing the error, because PHP only starts executing the code on the page once the file has been received, and it might do something with the POST request