先看下图:
在图中标注部分,会有取不到值的情况。
其实出现这个的原因是Servlet在socket上的读取只能一次。request.getParameter与request.getInputStream这两个系列的方法 能不能取到值, 就完全取决于你调用的先后顺序了。
除了request.getInputStream()及其他多个关联方法不能多次调用外,还有另外一个容易引起bug的地方:
在某个版本的springboot开始,会默认注入org.springframework.web.filter.HiddenHttpMethodFilter,这个Filter就会调用getParameter(),会导致用户代码中的getInputStream()返回空: https://github.com/spring-projects/spring-boot/issues/4782 https://github.com/spring-projects/spring-framework/issues/21439
一般来说,Trace当前使用的具体Servlet容器对应的方法,就能找到谁调用了getParameter()系列方法。 比如undertow实现是:io.undertow.servlet.spec.HttpServletRequestImpl#getParameter tomcat实现是:org.apache.catalina.connector.Request#parseParameters 有兴趣的可以去看看其他容器的实现。
在高可用架构Learning as we Go第五期的page 33有这样的介绍: 在读取了 http.Request.Body 之后, Body 就被排空了,而随后的读取就会返回 []byte{} —— 一个空的主文。 这是因为当你在读取http. Request.Body 的字节时,读取器处于这些字节的结尾,需要重置才能再次读取。但是, http.Request.Body 是一个 io.ReadWriter 并且没有Peek或Seek这样可以帮上忙的方法。一个解决这个问题的方法是先把主文复制进存储空间,然后在读取之后把原来的回拨回去。如果你的请求都很庞大这么做的成本很高。这绝对是一个让人恍然大悟,而且时不时还会让人措手不及的程序。 这个的原因和Servlet一样。
type Request struct { // Body is the request's body. // // For client requests a nil body means the request has no // body, such as a GET request. The HTTP Client's Transport // is responsible for calling the Close method. // // For server requests the Request Body is always non-nil // but will return EOF immediately when no body is present. // The Server will close the request body. The ServeHTTP // Handler does not need to. Body io.ReadCloser
// ... other fields elided ... }
package httputil // import "net/http/httputil"
func DumpRequest(req *http.Request, body bool) ([]byte, error) DumpRequest returns the given request in its HTTP/1.x wire representation. It should only be used by servers to debug client requests. The returned representation is an approximation only; some details of the initial request are lost while parsing it into an http.Request. In particular, the order and case of header field names are lost. The order of values in multi-valued headers is kept intact. HTTP/2 requests are dumped in HTTP/1.x form, not in their original binary representations.
If body is true, DumpRequest also returns the body. To do so, it consumes req.Body and then replaces it with a new io.ReadCloser that yields the same bytes. If DumpRequest returns an error, the state of req is undefined.
The documentation for http.Request.Write details which fields of req are included in the dump.
If body is true, DumpRequest also returns the body. To do so, it consumes req