vlambda博客
学习文章列表

Web应用调式之Tomcat限制读取速度

前言

在做文件上传时候,需要有进度条,但是后端写好接口,前端调用时由于是本地环境,所以上传速度非常快,通常100M下的文件都是秒上传,看不到进度条的变化,如果还需要调试一些其他信息,比如上传过程中取消,让后端接收的慢一些,就要做一些手段了。

但是你会发现,无论你在后端怎么写,前端进度依然还是秒上传,即使你通过字节流一个字节一个字节读取。

这其实不是你能控制的,原因在于Tomcat接受到请求后,它会全部读取完毕后在交给你处理,你在Servlet中任何操作,包括读取后Sleep一段时间,都是操作的Tomcat为你生成好的一个副本,这个时候文件已经在Tomcat中了,所以你任何操作都无济于事。

所以问题的根本在于,如何控制Tomcat的读取速度,但是找遍所有配置,Tomcat貌似没有给我们提供这样一个方法,所以还是要大动干辄去修改Tomcat的源码。

Tomcat读取Socket中的数据位于源码中NioEndpoint类下的fillReadBuffer方法,其中有下面这一句。

n = getSocket().read(buffer);

buffer是一个ByteBuffer类型,所以,他会有一个默认的容量。

这个默认值是8192,由SocketProperties类下的appReadBufSize字段控制,但是对于他setAppReadBufSize方法,貌似没有任何一处地方调用,所以我们只能通过这样去修改。

  /**
   * The application read buffer size in bytes.
   * Default value is rxBufSize
   */

  protected int appReadBufSize = 8192;

修改这里的值,比如是10,然后重新打包,命令是ant embed-jars,打包后的路径位于output/embed/tomcat-embed-core.jar

这个任务用于构建被第三方使用的依赖,SpringBoot就是引入的这个依赖。

然后在项目中重新引入这个依赖


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")
}        

这回就可以测试了。

在我这里测试,上传一个100M的文件也需要10秒,这个时候就可以慢慢调试了,但是,其他接口同样会受影响,因为Tomcat的读取速度一次就是10字节。

- END -