preface

In file upload, need to have a progress bar, but write the backend interface, front when the call is due to the local environment, so the upload speed is very block, usually 100 m under the uploaded files are seconds, can’t see the change of the progress bar, if you still need to debug some other information, such as cancel the upload process, let the back-end received slower, is about to do some means.

But you’ll find that no matter what you write on the back end, the front-end progress is still uploaded in seconds, even if you read byte by byte through the byte stream.

This is actually out of your control, the reason is that after Tomcat receives the request, it will read all the data and then hand it to you for processing. Any operation you do in the Servlet, including sleeping for some time after reading, is that Tomcat generates a good copy for you. At this time, the file is already in Tomcat. So there’s nothing you can do about it.

So the root of the problem is how to control the read speed of Tomcat, but after looking at all configurations, Tomcat does not seem to provide us with such a method, so we still have to do a lot of work to modify the source code of Tomcat.

Tomcat reads data from the Socket in the source NioEndpoint class fillReadBuffer method, which has the following sentence.

n = getSocket().read(buffer);
Copy the code

Buffer is a ByteBuffer, so it will have a default size.

The default value is 8192, controlled by the SocketProperties appReadBufSize field, but the setAppReadBufSize method doesn’t seem to be called anywhere, so we can only change it this way.

  /** * The application read buffer size in bytes. * Default value is rxBufSize */
  protected int appReadBufSize = 8192;
Copy the code

Change the value here, say 10, and repackage it with the command Ant embed-jars. The packaged path is at output/embed/tomcat-embed-core.jar.

This task is used to build dependencies that are used by third parties, and SpringBoot is the dependency that was introduced.

Then reintroduce this dependency in your project


implementation(files("embed/tomcat-embed-core.jar"))

implementation("org.springframework.boot:spring-boot-starter-web"){
    exclude(group="org.apache.tomcat.embed".module = "tomcat-embed-core")}Copy the code

Now you can test it.

In my tests, it took 10 seconds to upload a 100M file, at which point it was easy to debug, but the other interfaces suffered as well, as Tomcat’s read speed was 10 bytes at a time.