当向网页发出请求并且通过servlet(通过tomcat处理)处理它时,一旦在servlet级别(或spring mvc控制器)进入处理,就有整个请求头/身体的/ etc。已经从客户端发送到服务器了吗?
假设客户端正在对网页执行http POST,并且该帖子包含所有表单元素。
所有这些数据都将通过tomcat和您正在执行的servlet,或者如果您实际上没有引用:
request.getParamater("abc")
那么你不会因为它不会被流式传输而产生额外的负载?
答案 0 :(得分:14)
我找不到引用,但我相信servlet在整个头文件可用后开始处理(所有请求头后跟两个换行符)。这就是为什么您getInputStream()
和getReader()
而不是getBody()
返回String
或byte[]
。
这样,servlet可以在客户端仍然发送请求时开始处理请求数据,从而允许servlet处理大量内存占用的数据。例如,上传servlet可以逐字节读取上传的文件并将其保存到磁盘,而无需同时在内存中提供完整的请求内容。
这是我用于测试的servlet(在Scala中,对不起):
@WebServlet(Array("/upload"))
class UploadServlet extends HttpServlet {
@Override
override def doPost(request: HttpServletRequest, response: HttpServletResponse) {
println(request.getParameter("name"));
val input = Source.fromInputStream(request.getInputStream)
input.getLines() foreach println
println("Done")
}
}
现在我使用nc
来模拟慢客户端:
$ nc localhost 8080
服务器端没有任何事情发生。我现在手动发送一些HTTP标头:
POST /upload?name=foo HTTP/1.1
Host: localhost:8080
Content-Length: 10000000
服务器端仍未发生任何事情。 Tomcat接受了连接但尚未调用UploadServlet.doPost
。但是当我按下 Enter 两次时,servlet会打印name
参数,但会阻塞getLines()
(下面的getInputStream()
)。
我现在可以使用10000000
发送文本行(Tomcat需要nc
个字节)并在服务器端逐步打印(input.getLines()
返回Iterator[String]
阻塞,直到新线路可用。)
Tomcat在开始处理请求之前等待整个 HTTP标头(将其传递给匹配的servlet)
在doPost()
调用之前,请求正文不必完全可用。这很好,否则我们很快就会耗尽内存。
这同样适用于发送回复 - 我们可以逐步执行此操作。
使用Spring MVC,你必须要小心。考虑以下两种方法(注意不同的参数类型):
@Controller
@RequestMapping(value = Array("/upload"))
class UploadController {
@RequestMapping(value = Array("/good"), method = Array(POST))
@ResponseStatus(HttpStatus.NO_CONTENT)
def goodUpload(body: InputStream) {
//...
}
@RequestMapping(value = Array("/bad"), method = Array(POST))
@ResponseStatus(HttpStatus.NO_CONTENT)
def badUpload(@RequestBody body: Array[Byte]) {
//...
}
}
一旦收到HTTP标头,输入/upload/good
将调用goodUpload
处理程序方法但如果您还没有正文,则会尝试阅读body
InputStream
接收。
然而/upload/bad
将等到整个POST
正文可用,因为我们已明确请求整个正文作为字节数组(String
具有相同的效果):{{1 }}
因此,Spring MVC如何处理大型请求主体。
请记住,HTTP在TCP / IP之上工作。仅仅因为您没有调用@RequestBody body: Array[Byte]
/ getInputStream()
并不意味着服务器没有从客户端接收数据。实际上,操作系统管理网络套接字并保持接收未消耗的TCP / IP数据包。这意味着来自客户端的数据被推送到服务器,但操作系统必须缓冲该数据。
也许更有经验的人可以回答在这种情况下发生的事情(对于这个网站来说不是真正的问题)。如果服务器没有读取传入数据,O / S可能会突然关闭套接字,或者如果缓冲区变大,它可能只是缓冲它并交换?另一种解决方案可能是停止确认客户端数据包,导致客户端减速/停止。真的取决于O / S,而不是HTTP / servlets。